Skip to content
52 changes: 23 additions & 29 deletions CodeWalker.Core/GameFiles/Resources/Texture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -699,16 +699,27 @@ public int CalcDataSize()
var dxgifmt = DDSIO.GetDXGIFormat(Format);
int div = 1;
int len = 0;
bool compressed = DDSIO.DXTex.IsCompressed(dxgifmt);
int minimumLengthPerMip = compressed ? (IsBC1Based(dxgifmt) ? 8 : 16) : DDSIO.DXTex.BitsPerPixel(dxgifmt) / 8;
for (int i = 0; i < Levels; i++)
{
var width = Width / div;
var height = Height / div;
// Width or Height may reach 1 before the last mip level, half of 1 would be 0.5 truncated to 0.
// A texture can't have a dimension of 0, so we need to floor at 1.
var width = Math.Max(1, Width / div);
var height = Math.Max(1, Height / div);
DDSIO.DXTex.ComputePitch(dxgifmt, width, height, out var rowPitch, out var slicePitch, 0);
len += slicePitch;
len += Math.Max(minimumLengthPerMip, slicePitch);
div *= 2;
}

return len * Depth;
}

private bool IsBC1Based(DDSIO.DXGI_FORMAT format)
{
return format == DDSIO.DXGI_FORMAT.DXGI_FORMAT_BC1_TYPELESS || format == DDSIO.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM || format == DDSIO.DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM_SRGB;
}

public ushort CalculateStride()
{
if (Format == 0) return 0;
Expand Down Expand Up @@ -937,9 +948,15 @@ public override void Read(ResourceDataReader reader, params object[] parameters)
this.Unknown_84h = reader.ReadUInt32();
this.Unknown_88h = reader.ReadUInt32();
this.Unknown_8Ch = reader.ReadUInt32();


// Ignore stride loaded from file as it may be incorrect, especially if texture is ATI2 and the file was
// previously saved in OpenIV, DDS documentation recommends recalculating this anyway
DDSIO.DXTex.ComputePitch(DDSIO.GetDXGIFormat(Format), this.Width, this.Height, out int rowPitch, out int slicePitch, 0);
this.Stride = (ushort)rowPitch;

// read reference data
this.Data = reader.ReadBlockAt<TextureData>(this.DataPointer, this.Format, this.Width, this.Height, this.Levels, this.Stride);
this.Data = reader.ReadBlockAt<TextureData>(this.DataPointer, CalcDataSize());
//this.Format, this.Width, this.Height, this.Levels, this.Stride);

}
}
Expand Down Expand Up @@ -1086,30 +1103,7 @@ public override long BlockLength
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
if (reader.IsGen9)
{
int fullLength = Convert.ToInt32(parameters[0]);
FullData = reader.ReadBytes(fullLength);
}
else
{
uint format = Convert.ToUInt32(parameters[0]);
int Width = Convert.ToInt32(parameters[1]);
int Height = Convert.ToInt32(parameters[2]);
int Levels = Convert.ToInt32(parameters[3]);
int Stride = Convert.ToInt32(parameters[4]);

int fullLength = 0;
int length = Stride * Height;
for (int i = 0; i < Levels; i++)
{
fullLength += length;
length /= 4;
}

FullData = reader.ReadBytes(fullLength);
}

FullData = reader.ReadBytes((int)parameters[0]);
}

/// <summary>
Expand Down
23 changes: 13 additions & 10 deletions CodeWalker.Core/GameFiles/Utils/DDSIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,10 @@ private static Image[] GetMipmapImages(ImageStruct img, DXGI_FORMAT format)
int add = 0;
for (int i = 0; i < img.MipMapLevels; i++)
{
images[i].width = img.Width / div;
images[i].height = img.Height / div;
// Prevent width or height from becoming zero. One divided by anything will be < 1 which when cast to an
// int will be truncated to 0.
images[i].width = Math.Max(1, img.Width / div);
images[i].height = Math.Max(1, img.Height / div);
images[i].format = format; //(DXGI_FORMAT)img.Format;
images[i].pixels = buf + add;

Expand Down Expand Up @@ -2701,32 +2703,33 @@ private static void DecompressBC5Block(BinaryReader imageReader, int x, int y, i
r = (byte)(((6 - rIndex) * r0 + (rIndex - 1) * r1) / 5);
}


// Fixed copy and paste error? Most of these 'g's below were 'r's, which caused BC5 (ATI2) textures
// to not have correct colors.
byte g = 255;
uint gIndex = (uint)((gMask >> 3 * (4 * blockY + blockX)) & 0x07);
if (gIndex == 0)
{
r = r0;
g = g0;
}
else if (gIndex == 1)
{
r = r1;
g = g1;
}
else if (r0 > r1)
else if (g0 > g1)
{
r = (byte)(((8 - gIndex) * r0 + (gIndex - 1) * r1) / 7);
g = (byte)(((8 - gIndex) * g0 + (gIndex - 1) * g1) / 7);
}
else if (gIndex == 6)
{
r = 0;
g = 0;
}
else if (gIndex == 7)
{
r = 0xff;
g = 0xff;
}
else
{
r = (byte)(((6 - gIndex) * r0 + (gIndex - 1) * r1) / 5);
g = (byte)(((6 - gIndex) * g0 + (gIndex - 1) * g1) / 5);
}


Expand Down
6 changes: 4 additions & 2 deletions CodeWalker/Forms/YtdForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ private void ShowTextureMip(Texture tex, int mip, bool mipchange)
{
int cmip = Math.Min(Math.Max(mip, 0), tex.Levels - 1);
byte[] pixels = DDSIO.GetPixels(tex, cmip);
int w = tex.Width >> cmip;
int h = tex.Height >> cmip;
// Certain mipmap dimension reduction chains may lead this to become zero, so it should be clamped to be
// one at minimum.
int w = Math.Max(1, tex.Width >> cmip);
int h = Math.Max(1, tex.Height >> cmip);
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);

if (pixels != null)
Expand Down