diff --git a/CodeWalker.Core/CodeWalker.Core.csproj b/CodeWalker.Core/CodeWalker.Core.csproj index 43dc750..045ff6e 100644 --- a/CodeWalker.Core/CodeWalker.Core.csproj +++ b/CodeWalker.Core/CodeWalker.Core.csproj @@ -122,6 +122,7 @@ + diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index 0a1dbff..32d5e3b 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -186,7 +186,7 @@ namespace CodeWalker.GameFiles //TestCuts(); //TestYlds(); //TestYcds(); - //TestYtds(); + TestYtds(); //TestYbns(); //TestYdrs(); //TestYdds(); @@ -3440,6 +3440,7 @@ namespace CodeWalker.GameFiles } public void TestYtds() { + bool ddstest = true; bool savetest = false; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) @@ -3461,6 +3462,23 @@ namespace CodeWalker.GameFiles UpdateStatus("Error! " + ex.ToString()); errorfiles.Add(entry); } + if (ddstest && (ytdfile != null) && (ytdfile.TextureDict != null)) + { + foreach (var tex in ytdfile.TextureDict.Textures.data_items) + { + var dds = Utils.DDSIO.GetDDSFile(tex); + var tex2 = Utils.DDSIO.GetTexture(dds); + if (!tex.Name.StartsWith("script_rt")) + { + if (tex.Data?.FullData?.Length != tex2.Data?.FullData?.Length) + { } + if (tex.Stride != tex2.Stride) + { } + } + if ((tex.Format != tex2.Format) || (tex.Width != tex2.Width) || (tex.Height != tex2.Height) || (tex.Depth != tex2.Depth) || (tex.Levels != tex2.Levels)) + { } + } + } if (savetest && (ytdfile != null) && (ytdfile.TextureDict != null)) { var fentry = entry as RpfFileEntry; @@ -3687,7 +3705,7 @@ namespace CodeWalker.GameFiles } public void TestYdrs() { - bool savetest = true; + bool savetest = false; bool boundsonly = true; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) @@ -3800,7 +3818,7 @@ namespace CodeWalker.GameFiles } public void TestYfts() { - bool savetest = true; + bool savetest = false; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) { @@ -3855,6 +3873,7 @@ namespace CodeWalker.GameFiles } public void TestYpts() { + var savetest = false; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) { @@ -3875,7 +3894,7 @@ namespace CodeWalker.GameFiles UpdateStatus("Error! " + ex.ToString()); errorfiles.Add(entry); } - if ((ypt != null) && (ypt.PtfxList != null)) + if (savetest && (ypt != null) && (ypt.PtfxList != null)) { var fentry = entry as RpfFileEntry; if (fentry == null) diff --git a/CodeWalker.Core/GameFiles/Resources/Texture.cs b/CodeWalker.Core/GameFiles/Resources/Texture.cs index 8b0c977..44cfe68 100644 --- a/CodeWalker.Core/GameFiles/Resources/Texture.cs +++ b/CodeWalker.Core/GameFiles/Resources/Texture.cs @@ -22,7 +22,7 @@ namespace CodeWalker.GameFiles // structure data public uint Unknown_10h { get; set; } // 0x00000000 public uint Unknown_14h { get; set; } // 0x00000000 - public uint Unknown_18h { get; set; } // 0x00000001 + public uint Unknown_18h { get; set; } = 1; // 0x00000001 public uint Unknown_1Ch { get; set; } // 0x00000000 public ResourceSimpleList64_uint TextureNameHashes { get; set; } public ResourcePointerList64 Textures { get; set; } @@ -143,7 +143,7 @@ namespace CodeWalker.GameFiles // structure data public uint VFT { get; set; } - public uint Unknown_4h { get; set; } // 0x00000001 + public uint Unknown_4h { get; set; } = 1; // 0x00000001 public uint Unknown_8h { get; set; } // 0x00000000 public uint Unknown_Ch { get; set; } // 0x00000000 public uint Unknown_10h { get; set; } // 0x00000000 @@ -153,7 +153,8 @@ namespace CodeWalker.GameFiles public uint Unknown_20h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000 public ulong NamePointer { get; set; } - public uint Unknown_30h { get; set; } + public ushort Unknown_30h { get; set; } = 1; + public ushort Unknown_32h { get; set; } public uint Unknown_34h { get; set; } // 0x00000000 public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000 @@ -181,7 +182,8 @@ namespace CodeWalker.GameFiles this.Unknown_20h = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt32(); this.NamePointer = reader.ReadUInt64(); - this.Unknown_30h = reader.ReadUInt32(); + this.Unknown_30h = reader.ReadUInt16(); + this.Unknown_32h = reader.ReadUInt16(); this.Unknown_34h = reader.ReadUInt32(); this.Unknown_38h = reader.ReadUInt32(); this.Unknown_3Ch = reader.ReadUInt32(); @@ -195,6 +197,22 @@ namespace CodeWalker.GameFiles { NameHash = JenkHash.GenHash(Name.ToLowerInvariant()); } + + switch (Unknown_32h) + { + case 0x20: + case 0x28: + case 0x30: + case 0x38: + case 0x40: + case 0x48: + case 0x80: + case 0x90: + case 0x2://embedded + break; + default: + break; + } } /// @@ -218,6 +236,7 @@ namespace CodeWalker.GameFiles writer.Write(this.Unknown_24h); writer.Write(this.NamePointer); writer.Write(this.Unknown_30h); + writer.Write(this.Unknown_32h); writer.Write(this.Unknown_34h); writer.Write(this.Unknown_38h); writer.Write(this.Unknown_3Ch); @@ -251,13 +270,16 @@ namespace CodeWalker.GameFiles } // structure data - public uint Unknown_40h { get; set; } + public byte Unknown_40h { get; set; } + public byte Unknown_41h { get; set; } + public byte Unknown_42h { get; set; } + public byte Unknown_43h { get; set; } public uint Unknown_44h { get; set; } // 0x00000000 - public uint Unknown_48h { get; set; } + public uint Unknown_48h { get; set; } // 0, 1 public uint Unknown_4Ch { get; set; } // 0x00000000 public ushort Width { get; set; } public ushort Height { get; set; } - public ushort Unknown_54h { get; set; } // 0x0001 + public ushort Depth { get; set; } = 1; //is depth > 1 supported? public ushort Stride { get; set; } public TextureFormat Format { get; set; } public byte Unknown_5Ch { get; set; } // 0x00 @@ -299,13 +321,16 @@ namespace CodeWalker.GameFiles base.Read(reader, parameters); // read structure data - this.Unknown_40h = reader.ReadUInt32(); + this.Unknown_40h = reader.ReadByte(); + this.Unknown_41h = reader.ReadByte(); + this.Unknown_42h = reader.ReadByte(); + this.Unknown_43h = reader.ReadByte(); this.Unknown_44h = reader.ReadUInt32(); this.Unknown_48h = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32(); this.Width = reader.ReadUInt16(); this.Height = reader.ReadUInt16(); - this.Unknown_54h = reader.ReadUInt16(); + this.Depth = reader.ReadUInt16(); this.Stride = reader.ReadUInt16(); this.Format = (TextureFormat)reader.ReadUInt32(); this.Unknown_5Ch = reader.ReadByte(); @@ -332,6 +357,171 @@ namespace CodeWalker.GameFiles this.Levels, this.Stride ); + + switch (Unknown_40h) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 8: + case 9: + case 0xA: + case 0xB: + case 0xC: + case 0xE: + case 0x10: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x26: + case 0x34: + case 0x36: + case 0x37: + case 0x42: + case 0x54: + case 0x56: + case 0x57: + case 0x74: + case 0x76: + case 0x77: + case 0x20://embedded only + break; + default: + break; + } + switch (Unknown_41h) + { + case 0: + case 1: + case 2: + case 4: + case 6: + case 8: + case 0xA: + case 0xC: + case 0xE: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x16: + case 0x17: + case 0x18: + case 0x1C: + case 0x1E: + case 0x20: + case 0x22: + case 0x28: + case 0x2B: + case 0x2C: + case 0x30: + case 0x38: + case 0x39: + case 0x3C: + case 0x40: + case 0x4C: + case 0x4E: + case 0x50: + case 0x54: + case 0x56: + case 0x57: + case 0x58: + case 0x5A: + case 0x5C: + case 0x5E: + case 0x60: + case 0x64: + case 0x68: + case 0x70: + case 0x78: + case 0x80: + case 0x90: + case 0x9C: + case 0x9E: + case 0xA0: + case 0xA8: + case 0xAA: + case 0xAC: + case 0xAE: + case 0xB0: + case 0xB2: + case 0xB4: + case 0xB8: + case 0xBC: + case 0xC0: + case 0xD0: + case 7://embedded only + case 0xA4://embedded only + case 0xAB://embedded only + break; + default: + break; + } + switch (Unknown_42h) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 0xA: + case 0xB: + case 0xC: + case 0xE: + case 0x10: + case 0x12: + case 0x14: + case 0x15: + case 0x18: + case 0x19: + case 0x20: + case 0x21: + case 0x24: + case 0x2A: + case 0x40: + case 0x55: + case 0x80://embedded only + break; + default: + break; + } + switch (Unknown_43h) + { + case 0x20://32 + case 0x28://40 + case 0x30://48 + case 0: + break; + default: + break; + } + + switch (Unknown_48h) + { + case 0: + case 1: + break; + default: + break; + } + + } /// @@ -345,12 +535,15 @@ namespace CodeWalker.GameFiles // write structure data writer.Write(this.Unknown_40h); + writer.Write(this.Unknown_41h); + writer.Write(this.Unknown_42h); + writer.Write(this.Unknown_43h); writer.Write(this.Unknown_44h); writer.Write(this.Unknown_48h); writer.Write(this.Unknown_4Ch); writer.Write(this.Width); writer.Write(this.Height); - writer.Write(this.Unknown_54h); + writer.Write(this.Depth); writer.Write(this.Stride); writer.Write((uint)this.Format); writer.Write(this.Unknown_5Ch); diff --git a/Utils/DDSIO.cs b/CodeWalker.Core/GameFiles/Utils/DDSIO.cs similarity index 82% rename from Utils/DDSIO.cs rename to CodeWalker.Core/GameFiles/Utils/DDSIO.cs index d9b5a53..e99f363 100644 --- a/Utils/DDSIO.cs +++ b/CodeWalker.Core/GameFiles/Utils/DDSIO.cs @@ -69,6 +69,32 @@ +//additional dds importing code modified from: https://gist.github.com/spazzarama/2710d020d1d615cde20c607711655167 +// DDSTextureLoader Ported to C# by Justin Stenning, March 2017 +//-------------------------------------------------------------------------------------- +// File: DDSTextureLoader.cpp +// +// Functions for loading a DDS texture and creating a Direct3D runtime resource for it +// +// Note these functions are useful as a light-weight runtime loader for DDS files. For +// a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + + + + + using CodeWalker.GameFiles; using System; using System.Collections.Generic; @@ -332,7 +358,142 @@ namespace CodeWalker.Utils } + public static Texture GetTexture(byte[] ddsfile) + { + var ms = new MemoryStream(ddsfile); + var br = new BinaryReader(ms); + var header = new DDS_HEADER(); + var header10 = new DDS_HEADER_DXT10(); + var useheader10 = false; + + if (!DXTex._ReadDDSHeader(br, out header, out header10, out useheader10)) + { return null; } + + var width = header.dwWidth; + var height = header.dwHeight; + var depth = header.dwDepth; + var mipCount = header.dwMipMapCount; + if (mipCount == 0) + { + mipCount = 1; + } + + TEX_DIMENSION resDim = 0; + uint arraySize = 1; + DXGI_FORMAT format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN; + bool isCubeMap = false; + + if (useheader10) + { + arraySize = header10.arraySize; + format = header10.dxgiFormat; + resDim = (TEX_DIMENSION)header10.resourceDimension; + + if (arraySize == 0) throw new Exception("ArraySize was 0! This isn't supported..."); + switch (format) + { + case DXGI_FORMAT.DXGI_FORMAT_AI44: + case DXGI_FORMAT.DXGI_FORMAT_IA44: + case DXGI_FORMAT.DXGI_FORMAT_P8: + case DXGI_FORMAT.DXGI_FORMAT_A8P8: + throw new NotSupportedException(string.Format("{0} DXGI format is not supported", format.ToString())); + default: + if (DXTex.BitsPerPixel(format) == 0) + throw new NotSupportedException(string.Format("{0} DXGI format is not supported", format.ToString())); + break; + } + switch (resDim) + { + case TEX_DIMENSION.TEX_DIMENSION_TEXTURE1D: + if ((header.dwFlags & DXTex.DDS_HEIGHT) > 0 && height != 1) throw new NotSupportedException("1D texture's height wasn't 1!"); + height = depth = 1; // D3DX writes 1D textures with a fixed Height of 1 + break; + case TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D: + if ((header10.miscFlag & (uint)TEX_MISC_FLAG.TEX_MISC_TEXTURECUBE) > 0) { arraySize *= 6; isCubeMap = true; } + depth = 1; + break; + case TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D: + if ((header.dwFlags & DXTex.DDS_HEADER_FLAGS_VOLUME) == 0) throw new ArgumentException("3D texture without volume flag!"); + if (arraySize > 1) throw new ArgumentException("3D texture with ArraySize > 1!"); + break; + default: throw new ArgumentException("Unknown resource dimension!"); + } + } + else + { + format = header.ddspf.GetDXGIFormat(); + + if (format == DXGI_FORMAT.DXGI_FORMAT_UNKNOWN) throw new ArgumentException("Unknown DDS format."); + if ((header.dwFlags & DXTex.DDS_HEADER_FLAGS_VOLUME) > 0) + { + resDim = TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D; + } + else + { + if ((header.dwCaps2 & DXTex.DDS_CUBEMAP) > 0) + { + if ((header.dwCaps2 & DXTex.DDS_CUBEMAP_ALLFACES) != DXTex.DDS_CUBEMAP_ALLFACES) throw new ArgumentException("Not all faces in cubemap exist!");//requires all 6 faces + arraySize = 6; + isCubeMap = true; + } + depth = 1; + resDim = TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D; + // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture + } + if (DXTex.BitsPerPixel(format) == 0) throw new Exception(string.Format("{0} DXGI format is not supported", format.ToString())); + } + + if (isCubeMap) + { } + + DXTex.ComputePitch(format, (int)width, (int)height, out int rowPitch, out int slicePitch, 0); + var stride = slicePitch / height; + var scanlines = DXTex.ComputeScanlines(format, (int)height); + + var brem = ms.Length - ms.Position; + var ddsdata = br.ReadBytes((int)brem); + + var tex = new Texture(); + tex.Width = (ushort)width; + tex.Height = (ushort)height; + tex.Depth = (ushort)depth; + tex.Levels = (byte)mipCount; + tex.Format = GetTextureFormat(format); + tex.Stride = (ushort)stride; + tex.Data = new TextureData(); + tex.Data.FullData = ddsdata; + + //tex.Unknown_43h = (byte)header.ddspf.dwSize; + + return tex; + } + + + + + private static TextureFormat GetTextureFormat(DXGI_FORMAT f) + { + var format = (TextureFormat)0; + switch (f) + { + // compressed + case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM: format = TextureFormat.D3DFMT_DXT1; break; + case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM: format = TextureFormat.D3DFMT_DXT3; break; + case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM: format = TextureFormat.D3DFMT_DXT5; break; + case DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM: format = TextureFormat.D3DFMT_ATI1; break; + case DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM: format = TextureFormat.D3DFMT_ATI2; break; + case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM: format = TextureFormat.D3DFMT_BC7; break; + + // uncompressed + case DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM: format = TextureFormat.D3DFMT_A1R5G5B5; break; + case DXGI_FORMAT.DXGI_FORMAT_A8_UNORM: format = TextureFormat.D3DFMT_A8; break; + case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM: format = TextureFormat.D3DFMT_A8B8G8R8; break; + case DXGI_FORMAT.DXGI_FORMAT_R8_UNORM: format = TextureFormat.D3DFMT_L8; break; + case DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM: format = TextureFormat.D3DFMT_A8R8G8B8; break; + } + return format; + } private static DXGI_FORMAT GetDXGIFormat(TextureFormat f) { @@ -1015,6 +1176,7 @@ namespace CodeWalker.Utils public static uint DDS_FLAGS_VOLUME = 0x00200000; // DDSCAPS2_VOLUME + public static uint DDS_MAGIC = 0x20534444; // "DDS " @@ -1104,7 +1266,6 @@ namespace CodeWalker.Utils int sizeofddsheader = 31 * 4; int sizeofddsheader10 = 5 * 4; - const uint DDS_MAGIC = 0x20534444; // "DDS " required = 4/*sizeof(uint32_t)*/ + sizeofddsheader/*sizeof(DDS_HEADER)*/; @@ -1313,6 +1474,68 @@ namespace CodeWalker.Utils } + public static bool _ReadDDSHeader(BinaryReader br, out DDS_HEADER header, out DDS_HEADER_DXT10 header10, out bool useheader10) + { + var magic = br.ReadUInt32(); + if (magic != DDS_MAGIC) throw new Exception("Invalid DDS magic!"); + + //var header = new DDS_HEADER(); + //var header10 = new DDS_HEADER_DXT10(); + int sizeofddsheader = 31 * 4; + int sizeofddspixelformat = 8 * 4; + + header.dwSize = br.ReadUInt32(); + header.dwFlags = br.ReadUInt32(); + header.dwHeight = br.ReadUInt32(); + header.dwWidth = br.ReadUInt32(); + header.dwPitchOrLinearSize = br.ReadUInt32(); + header.dwDepth = br.ReadUInt32(); // only if DDS_HEADER_FLAGS_VOLUME is set in dwFlags + header.dwMipMapCount = br.ReadUInt32(); + + //public uint dwReserved1[11]; //x11 + for (int i = 0; i < 11; i++) br.ReadUInt32(); + + header.ddspf.dwSize = br.ReadUInt32(); + header.ddspf.dwFlags = br.ReadUInt32(); + header.ddspf.dwFourCC = br.ReadUInt32(); + header.ddspf.dwRGBBitCount = br.ReadUInt32(); + header.ddspf.dwRBitMask = br.ReadUInt32(); + header.ddspf.dwGBitMask = br.ReadUInt32(); + header.ddspf.dwBBitMask = br.ReadUInt32(); + header.ddspf.dwABitMask = br.ReadUInt32(); + + header.dwCaps = br.ReadUInt32(); + header.dwCaps2 = br.ReadUInt32(); + header.dwCaps3 = br.ReadUInt32(); + header.dwCaps4 = br.ReadUInt32(); + header.dwReserved2 = br.ReadUInt32(); + + + + if(((DDS_PIXELFORMAT.DDS_FOURCC & header.ddspf.dwFlags) > 0) && + (DDS_PIXELFORMAT.MAKEFOURCC('D', 'X', '1', '0') == header.ddspf.dwFourCC)) + { + header10.dxgiFormat = (DXGI_FORMAT)br.ReadUInt32(); + header10.resourceDimension = br.ReadUInt32(); + header10.miscFlag = br.ReadUInt32(); // see DDS_RESOURCE_MISC_FLAG + header10.arraySize = br.ReadUInt32(); + header10.miscFlags2 = br.ReadUInt32(); // see DDS_MISC_FLAGS2 + useheader10 = true; + } + else + { + header10 = new DDS_HEADER_DXT10(); + useheader10 = false; + } + + if (header.dwSize != sizeofddsheader || header.ddspf.dwSize != sizeofddspixelformat) + { + throw new Exception("Invalid DDS header size"); + } + + + return true; + } } @@ -1596,86 +1819,250 @@ namespace CodeWalker.Utils public static uint DDS_PAL8 = 0x00000020; // DDPF_PALETTEINDEXED8 - public static DDS_PIXELFORMAT DDSPF_DXT1 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 ); - - public static DDS_PIXELFORMAT DDSPF_DXT2 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_DXT3 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_DXT4 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_DXT5 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_BC4_UNORM = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_BC4_SNORM = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_BC5_UNORM = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_BC5_SNORM = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_G8R8_G8B8 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_YUY2 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0); - - public static DDS_PIXELFORMAT DDSPF_A8R8G8B8 = new DDS_PIXELFORMAT( - 32, DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); - - public static DDS_PIXELFORMAT DDSPF_X8R8G8B8 = new DDS_PIXELFORMAT( - 32, DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); - - public static DDS_PIXELFORMAT DDSPF_A8B8G8R8 = new DDS_PIXELFORMAT( - 32, DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); - - public static DDS_PIXELFORMAT DDSPF_X8B8G8R8 = new DDS_PIXELFORMAT( - 32, DDS_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000); - - public static DDS_PIXELFORMAT DDSPF_G16R16 = new DDS_PIXELFORMAT( - 32, DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000); - - public static DDS_PIXELFORMAT DDSPF_R5G6B5 = new DDS_PIXELFORMAT( - 32, DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000); - - public static DDS_PIXELFORMAT DDSPF_A1R5G5B5 = new DDS_PIXELFORMAT( - 32, DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000); - - public static DDS_PIXELFORMAT DDSPF_A4R4G4B4 = new DDS_PIXELFORMAT( - 32, DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000); - - public static DDS_PIXELFORMAT DDSPF_R8G8B8 = new DDS_PIXELFORMAT( - 32, DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); - - public static DDS_PIXELFORMAT DDSPF_L8 = new DDS_PIXELFORMAT( - 32, DDS_LUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00); - - public static DDS_PIXELFORMAT DDSPF_L16 = new DDS_PIXELFORMAT( - 32, DDS_LUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000); - - public static DDS_PIXELFORMAT DDSPF_A8L8 = new DDS_PIXELFORMAT( - 32, DDS_LUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00); - - public static DDS_PIXELFORMAT DDSPF_A8 = new DDS_PIXELFORMAT( - 32, DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff); + public static DDS_PIXELFORMAT DDSPF_DXT1 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 ); + public static DDS_PIXELFORMAT DDSPF_DXT2 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_DXT3 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_DXT4 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_DXT5 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_BC4_UNORM = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_BC4_SNORM = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_BC5_UNORM = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_BC5_SNORM = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_G8R8_G8B8 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_YUY2 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_A8R8G8B8 = new DDS_PIXELFORMAT(32, DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + public static DDS_PIXELFORMAT DDSPF_X8R8G8B8 = new DDS_PIXELFORMAT(32, DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); + public static DDS_PIXELFORMAT DDSPF_A8B8G8R8 = new DDS_PIXELFORMAT(32, DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + public static DDS_PIXELFORMAT DDSPF_X8B8G8R8 = new DDS_PIXELFORMAT(32, DDS_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000); + public static DDS_PIXELFORMAT DDSPF_G16R16 = new DDS_PIXELFORMAT(32, DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000); + public static DDS_PIXELFORMAT DDSPF_R5G6B5 = new DDS_PIXELFORMAT(32, DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000); + public static DDS_PIXELFORMAT DDSPF_A1R5G5B5 = new DDS_PIXELFORMAT(32, DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000); + public static DDS_PIXELFORMAT DDSPF_A4R4G4B4 = new DDS_PIXELFORMAT(32, DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000); + public static DDS_PIXELFORMAT DDSPF_R8G8B8 = new DDS_PIXELFORMAT(32, DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); + public static DDS_PIXELFORMAT DDSPF_L8 = new DDS_PIXELFORMAT(32, DDS_LUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00); + public static DDS_PIXELFORMAT DDSPF_L16 = new DDS_PIXELFORMAT(32, DDS_LUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000); + public static DDS_PIXELFORMAT DDSPF_A8L8 = new DDS_PIXELFORMAT(32, DDS_LUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00); + public static DDS_PIXELFORMAT DDSPF_A8 = new DDS_PIXELFORMAT(32, DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff); // D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue // This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat) - public static DDS_PIXELFORMAT DDSPF_DX10 = new DDS_PIXELFORMAT( - 32, DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0); + public static DDS_PIXELFORMAT DDSPF_DX10 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0); + + + + + + private bool ISBITMASK(uint r, uint g, uint b, uint a) + { + return ((dwRBitMask == r) && (dwGBitMask == g) && (dwBBitMask == b) && (dwABitMask == a)); + } + + public DXGI_FORMAT GetDXGIFormat() + { + + if ((dwFlags & DDS_RGB) > 0) + { + // Note that sRGB formats are written using the "DX10" extended header + + switch (dwRGBBitCount) + { + case 32: + if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM; + } + + if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM; + } + + if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_B8G8R8X8_UNORM; + } + + // No DXGI format maps to ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000) aka D3DFMT_X8B8G8R8 + + // Note that many common DDS reader/writers (including D3DX) swap the + // the RED/BLUE masks for 10:10:10:2 formats. We assumme + // below that the 'backwards' header mask is being used since it is most + // likely written by D3DX. The more robust solution is to use the 'DX10' + // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly + + // For 'correct' writers, this should be 0x000003ff, 0x000ffc00, 0x3ff00000 for RGB data + if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_R10G10B10A2_UNORM; + } + + // No DXGI format maps to ISBITMASK(0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000) aka D3DFMT_A2R10G10B10 + + if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_R16G16_UNORM; + } + + if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000)) + { + // Only 32-bit color channel format in D3D9 was R32F + return DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114 + } + break; + + case 24: + // No 24bpp DXGI formats aka D3DFMT_R8G8B8 + break; + + case 16: + if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000)) + { + return DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM; + } + if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000)) + { + return DXGI_FORMAT.DXGI_FORMAT_B5G6R5_UNORM; + } + + // No DXGI format maps to ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x0000) aka D3DFMT_X1R5G5B5 + if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0xf000)) + { + return DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM; + } + + // No DXGI format maps to ISBITMASK(0x0f00, 0x00f0, 0x000f, 0x0000) aka D3DFMT_X4R4G4B4 + + // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc. + break; + } + } + else if ((dwFlags & DDS_LUMINANCE) > 0) + { + if (8 == dwRGBBitCount) + { + if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x00000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension + } + + // No DXGI format maps to ISBITMASK(0x0f, 0x00, 0x00, 0xf0) aka D3DFMT_A4L4 + } + + if (16 == dwRGBBitCount) + { + if (ISBITMASK(0x0000ffff, 0x00000000, 0x00000000, 0x00000000)) + { + return DXGI_FORMAT.DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension + } + if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00)) + { + return DXGI_FORMAT.DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension + } + } + } + else if ((dwFlags & DDS_ALPHA) > 0) + { + if (8 == dwRGBBitCount) + { + return DXGI_FORMAT.DXGI_FORMAT_A8_UNORM; + } + } + else if ((dwFlags & DDS_FOURCC) > 0) + { + if (MAKEFOURCC('D', 'X', 'T', '1') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM; + } + if (MAKEFOURCC('D', 'X', 'T', '3') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; + } + if (MAKEFOURCC('D', 'X', 'T', '5') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; + } + + // While pre-mulitplied alpha isn't directly supported by the DXGI formats, + // they are basically the same as these BC formats so they can be mapped + if (MAKEFOURCC('D', 'X', 'T', '2') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM; + } + if (MAKEFOURCC('D', 'X', 'T', '4') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM; + } + + if (MAKEFOURCC('A', 'T', 'I', '1') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM; + } + if (MAKEFOURCC('B', 'C', '4', 'U') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM; + } + if (MAKEFOURCC('B', 'C', '4', 'S') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC4_SNORM; + } + + if (MAKEFOURCC('A', 'T', 'I', '2') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM; + } + if (MAKEFOURCC('B', 'C', '5', 'U') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM; + } + if (MAKEFOURCC('B', 'C', '5', 'S') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_BC5_SNORM; + } + + // BC6H and BC7 are written using the "DX10" extended header + + if (MAKEFOURCC('R', 'G', 'B', 'G') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_R8G8_B8G8_UNORM; + } + if (MAKEFOURCC('G', 'R', 'G', 'B') == dwFourCC) + { + return DXGI_FORMAT.DXGI_FORMAT_G8R8_G8B8_UNORM; + } + + // Check for D3DFORMAT enums being set here + switch (dwFourCC) + { + case 36: // D3DFMT_A16B16G16R16 + return DXGI_FORMAT.DXGI_FORMAT_R16G16B16A16_UNORM; + + case 110: // D3DFMT_Q16W16V16U16 + return DXGI_FORMAT.DXGI_FORMAT_R16G16B16A16_SNORM; + + case 111: // D3DFMT_R16F + return DXGI_FORMAT.DXGI_FORMAT_R16_FLOAT; + + case 112: // D3DFMT_G16R16F + return DXGI_FORMAT.DXGI_FORMAT_R16G16_FLOAT; + + case 113: // D3DFMT_A16B16G16R16F + return DXGI_FORMAT.DXGI_FORMAT_R16G16B16A16_FLOAT; + + case 114: // D3DFMT_R32F + return DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT; + + case 115: // D3DFMT_G32R32F + return DXGI_FORMAT.DXGI_FORMAT_R32G32_FLOAT; + + case 116: // D3DFMT_A32B32G32R32F + return DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT; + } + } + + return DXGI_FORMAT.DXGI_FORMAT_UNKNOWN; + } }; diff --git a/CodeWalker.Core/Utils/FbxConverter.cs b/CodeWalker.Core/Utils/FbxConverter.cs index 2e1f0c6..a49de4e 100644 --- a/CodeWalker.Core/Utils/FbxConverter.cs +++ b/CodeWalker.Core/Utils/FbxConverter.cs @@ -788,7 +788,8 @@ namespace CodeWalker } var texParam = new TextureBase(); texParam.Unknown_4h = 1; - texParam.Unknown_30h = 131073;//wtf is this? 2x shorts, 0x00020001 + texParam.Unknown_30h = 1;// 131073;//wtf is this? 2x shorts, 0x00020001 + texParam.Unknown_32h = 2; texParam.Name = name; texParam.NameHash = JenkHash.GenHash(name.ToLowerInvariant()); return texParam; diff --git a/CodeWalker.csproj b/CodeWalker.csproj index c8c6bb4..f4f0b20 100644 --- a/CodeWalker.csproj +++ b/CodeWalker.csproj @@ -612,7 +612,6 @@ TextInputForm.cs -