DDS file import code, Texture unknowns research

This commit is contained in:
dexy 2020-01-17 04:32:47 +11:00
parent 529eb779a4
commit c59047bdee
6 changed files with 693 additions and 93 deletions

View File

@ -122,6 +122,7 @@
<Compile Include="GameFiles\RpfFile.cs" /> <Compile Include="GameFiles\RpfFile.cs" />
<Compile Include="GameFiles\RpfManager.cs" /> <Compile Include="GameFiles\RpfManager.cs" />
<Compile Include="GameFiles\Utils\Data.cs" /> <Compile Include="GameFiles\Utils\Data.cs" />
<Compile Include="GameFiles\Utils\DDSIO.cs" />
<Compile Include="GameFiles\Utils\GTACrypto.cs" /> <Compile Include="GameFiles\Utils\GTACrypto.cs" />
<Compile Include="GameFiles\Utils\GTAKeys.cs" /> <Compile Include="GameFiles\Utils\GTAKeys.cs" />
<Compile Include="GameFiles\Utils\Jenk.cs" /> <Compile Include="GameFiles\Utils\Jenk.cs" />

View File

@ -186,7 +186,7 @@ namespace CodeWalker.GameFiles
//TestCuts(); //TestCuts();
//TestYlds(); //TestYlds();
//TestYcds(); //TestYcds();
//TestYtds(); TestYtds();
//TestYbns(); //TestYbns();
//TestYdrs(); //TestYdrs();
//TestYdds(); //TestYdds();
@ -3440,6 +3440,7 @@ namespace CodeWalker.GameFiles
} }
public void TestYtds() public void TestYtds()
{ {
bool ddstest = true;
bool savetest = false; bool savetest = false;
var errorfiles = new List<RpfEntry>(); var errorfiles = new List<RpfEntry>();
foreach (RpfFile file in AllRpfs) foreach (RpfFile file in AllRpfs)
@ -3461,6 +3462,23 @@ namespace CodeWalker.GameFiles
UpdateStatus("Error! " + ex.ToString()); UpdateStatus("Error! " + ex.ToString());
errorfiles.Add(entry); 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)) if (savetest && (ytdfile != null) && (ytdfile.TextureDict != null))
{ {
var fentry = entry as RpfFileEntry; var fentry = entry as RpfFileEntry;
@ -3687,7 +3705,7 @@ namespace CodeWalker.GameFiles
} }
public void TestYdrs() public void TestYdrs()
{ {
bool savetest = true; bool savetest = false;
bool boundsonly = true; bool boundsonly = true;
var errorfiles = new List<RpfEntry>(); var errorfiles = new List<RpfEntry>();
foreach (RpfFile file in AllRpfs) foreach (RpfFile file in AllRpfs)
@ -3800,7 +3818,7 @@ namespace CodeWalker.GameFiles
} }
public void TestYfts() public void TestYfts()
{ {
bool savetest = true; bool savetest = false;
var errorfiles = new List<RpfEntry>(); var errorfiles = new List<RpfEntry>();
foreach (RpfFile file in AllRpfs) foreach (RpfFile file in AllRpfs)
{ {
@ -3855,6 +3873,7 @@ namespace CodeWalker.GameFiles
} }
public void TestYpts() public void TestYpts()
{ {
var savetest = false;
var errorfiles = new List<RpfEntry>(); var errorfiles = new List<RpfEntry>();
foreach (RpfFile file in AllRpfs) foreach (RpfFile file in AllRpfs)
{ {
@ -3875,7 +3894,7 @@ namespace CodeWalker.GameFiles
UpdateStatus("Error! " + ex.ToString()); UpdateStatus("Error! " + ex.ToString());
errorfiles.Add(entry); errorfiles.Add(entry);
} }
if ((ypt != null) && (ypt.PtfxList != null)) if (savetest && (ypt != null) && (ypt.PtfxList != null))
{ {
var fentry = entry as RpfFileEntry; var fentry = entry as RpfFileEntry;
if (fentry == null) if (fentry == null)

View File

@ -22,7 +22,7 @@ namespace CodeWalker.GameFiles
// structure data // structure data
public uint Unknown_10h { get; set; } // 0x00000000 public uint Unknown_10h { get; set; } // 0x00000000
public uint Unknown_14h { 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 uint Unknown_1Ch { get; set; } // 0x00000000
public ResourceSimpleList64_uint TextureNameHashes { get; set; } public ResourceSimpleList64_uint TextureNameHashes { get; set; }
public ResourcePointerList64<Texture> Textures { get; set; } public ResourcePointerList64<Texture> Textures { get; set; }
@ -143,7 +143,7 @@ namespace CodeWalker.GameFiles
// structure data // structure data
public uint VFT { get; set; } 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_8h { get; set; } // 0x00000000
public uint Unknown_Ch { get; set; } // 0x00000000 public uint Unknown_Ch { get; set; } // 0x00000000
public uint Unknown_10h { 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_20h { get; set; } // 0x00000000
public uint Unknown_24h { get; set; } // 0x00000000 public uint Unknown_24h { get; set; } // 0x00000000
public ulong NamePointer { get; set; } 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_34h { get; set; } // 0x00000000
public uint Unknown_38h { get; set; } // 0x00000000 public uint Unknown_38h { get; set; } // 0x00000000
public uint Unknown_3Ch { get; set; } // 0x00000000 public uint Unknown_3Ch { get; set; } // 0x00000000
@ -181,7 +182,8 @@ namespace CodeWalker.GameFiles
this.Unknown_20h = reader.ReadUInt32(); this.Unknown_20h = reader.ReadUInt32();
this.Unknown_24h = reader.ReadUInt32(); this.Unknown_24h = reader.ReadUInt32();
this.NamePointer = reader.ReadUInt64(); 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_34h = reader.ReadUInt32();
this.Unknown_38h = reader.ReadUInt32(); this.Unknown_38h = reader.ReadUInt32();
this.Unknown_3Ch = reader.ReadUInt32(); this.Unknown_3Ch = reader.ReadUInt32();
@ -195,6 +197,22 @@ namespace CodeWalker.GameFiles
{ {
NameHash = JenkHash.GenHash(Name.ToLowerInvariant()); 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;
}
} }
/// <summary> /// <summary>
@ -218,6 +236,7 @@ namespace CodeWalker.GameFiles
writer.Write(this.Unknown_24h); writer.Write(this.Unknown_24h);
writer.Write(this.NamePointer); writer.Write(this.NamePointer);
writer.Write(this.Unknown_30h); writer.Write(this.Unknown_30h);
writer.Write(this.Unknown_32h);
writer.Write(this.Unknown_34h); writer.Write(this.Unknown_34h);
writer.Write(this.Unknown_38h); writer.Write(this.Unknown_38h);
writer.Write(this.Unknown_3Ch); writer.Write(this.Unknown_3Ch);
@ -251,13 +270,16 @@ namespace CodeWalker.GameFiles
} }
// structure data // 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_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 uint Unknown_4Ch { get; set; } // 0x00000000
public ushort Width { get; set; } public ushort Width { get; set; }
public ushort Height { 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 ushort Stride { get; set; }
public TextureFormat Format { get; set; } public TextureFormat Format { get; set; }
public byte Unknown_5Ch { get; set; } // 0x00 public byte Unknown_5Ch { get; set; } // 0x00
@ -299,13 +321,16 @@ namespace CodeWalker.GameFiles
base.Read(reader, parameters); base.Read(reader, parameters);
// read structure data // 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_44h = reader.ReadUInt32();
this.Unknown_48h = reader.ReadUInt32(); this.Unknown_48h = reader.ReadUInt32();
this.Unknown_4Ch = reader.ReadUInt32(); this.Unknown_4Ch = reader.ReadUInt32();
this.Width = reader.ReadUInt16(); this.Width = reader.ReadUInt16();
this.Height = reader.ReadUInt16(); this.Height = reader.ReadUInt16();
this.Unknown_54h = reader.ReadUInt16(); this.Depth = reader.ReadUInt16();
this.Stride = reader.ReadUInt16(); this.Stride = reader.ReadUInt16();
this.Format = (TextureFormat)reader.ReadUInt32(); this.Format = (TextureFormat)reader.ReadUInt32();
this.Unknown_5Ch = reader.ReadByte(); this.Unknown_5Ch = reader.ReadByte();
@ -332,6 +357,171 @@ namespace CodeWalker.GameFiles
this.Levels, this.Levels,
this.Stride 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;
}
} }
/// <summary> /// <summary>
@ -345,12 +535,15 @@ namespace CodeWalker.GameFiles
// write structure data // write structure data
writer.Write(this.Unknown_40h); 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_44h);
writer.Write(this.Unknown_48h); writer.Write(this.Unknown_48h);
writer.Write(this.Unknown_4Ch); writer.Write(this.Unknown_4Ch);
writer.Write(this.Width); writer.Write(this.Width);
writer.Write(this.Height); writer.Write(this.Height);
writer.Write(this.Unknown_54h); writer.Write(this.Depth);
writer.Write(this.Stride); writer.Write(this.Stride);
writer.Write((uint)this.Format); writer.Write((uint)this.Format);
writer.Write(this.Unknown_5Ch); writer.Write(this.Unknown_5Ch);

View File

@ -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 CodeWalker.GameFiles;
using System; using System;
using System.Collections.Generic; 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) 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_FLAGS_VOLUME = 0x00200000; // DDSCAPS2_VOLUME
public static uint DDS_MAGIC = 0x20534444; // "DDS "
@ -1104,7 +1266,6 @@ namespace CodeWalker.Utils
int sizeofddsheader = 31 * 4; int sizeofddsheader = 31 * 4;
int sizeofddsheader10 = 5 * 4; int sizeofddsheader10 = 5 * 4;
const uint DDS_MAGIC = 0x20534444; // "DDS "
required = 4/*sizeof(uint32_t)*/ + sizeofddsheader/*sizeof(DDS_HEADER)*/; 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 uint DDS_PAL8 = 0x00000020; // DDPF_PALETTEINDEXED8
public static DDS_PIXELFORMAT DDSPF_DXT1 = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_DXT1 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 );
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_DXT2 = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_DXT4 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0);
32, DDS_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 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_DXT3 = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_BC4_SNORM = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0);
32, DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 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_DXT4 = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0);
32, DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 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_DXT5 = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_A8R8G8B8 = new DDS_PIXELFORMAT(32, DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
32, DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0); 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_BC4_UNORM = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_X8B8G8R8 = new DDS_PIXELFORMAT(32, DDS_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
32, DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0); 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_BC4_SNORM = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_A1R5G5B5 = new DDS_PIXELFORMAT(32, DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000);
32, DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0); 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_BC5_UNORM = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_L8 = new DDS_PIXELFORMAT(32, DDS_LUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00);
32, DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0); 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_BC5_SNORM = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_A8 = new DDS_PIXELFORMAT(32, DDS_ALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff);
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 // 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) // This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)
public static DDS_PIXELFORMAT DDSPF_DX10 = new DDS_PIXELFORMAT( public static DDS_PIXELFORMAT DDSPF_DX10 = new DDS_PIXELFORMAT(32, DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0);
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;
}
}; };

View File

@ -788,7 +788,8 @@ namespace CodeWalker
} }
var texParam = new TextureBase(); var texParam = new TextureBase();
texParam.Unknown_4h = 1; 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.Name = name;
texParam.NameHash = JenkHash.GenHash(name.ToLowerInvariant()); texParam.NameHash = JenkHash.GenHash(name.ToLowerInvariant());
return texParam; return texParam;

View File

@ -612,7 +612,6 @@
<Compile Include="Utils\TextInputForm.Designer.cs"> <Compile Include="Utils\TextInputForm.Designer.cs">
<DependentUpon>TextInputForm.cs</DependentUpon> <DependentUpon>TextInputForm.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Utils\DDSIO.cs" />
<Compile Include="Utils\GTAFolder.cs" /> <Compile Include="Utils\GTAFolder.cs" />
<Compile Include="Utils\InputUtils.cs" /> <Compile Include="Utils\InputUtils.cs" />
<Compile Include="Utils\MapUtils.cs" /> <Compile Include="Utils\MapUtils.cs" />