Tons more DDS fixes from yesterday. RGB textures also aren't blue anymore.

This commit is contained in:
KillzXGaming 2019-05-22 15:26:25 -04:00
parent a921e46a8f
commit 3a85f06ac7
15 changed files with 268 additions and 54 deletions

Binary file not shown.

View file

@ -163,6 +163,12 @@ namespace Bfres.Structs
if (setting.DataBlockOutput != null)
{
var surface = GTXSwizzle.CreateGx2Texture(setting.DataBlockOutput[0], setting);
surface.compSel = new byte[4];
surface.compSel[0] = (byte)setting.RedComp;
surface.compSel[1] = (byte)setting.GreenComp;
surface.compSel[2] = (byte)setting.BlueComp;
surface.compSel[3] = (byte)setting.alphaRef;
var tex = FromGx2Surface(surface, setting.TexName);
UpdateTex(tex);
@ -182,7 +188,12 @@ namespace Bfres.Structs
}
public override void Replace(string FileName) {
ReplaceTexture(FileName, Format);
//If the mipcount is originally 1 it's probably important so set it as default
if (texture != null && texture.MipCount == 1)
ReplaceTexture(FileName, Format, texture.MipCount);
else
ReplaceTexture(FileName, Format);
}
public void ReplaceTexture(string FileName, TEX_FORMAT DefaultFormat = TEX_FORMAT.UNKNOWN, uint MipMapCount = 0, TEX_FORMAT[] SupportedFormats = null,
@ -336,13 +347,20 @@ namespace Bfres.Structs
}
tex.Height = surf.height;
tex.Width = surf.width;
tex.Regs = new uint[5];
tex.ArrayLength = 1;
var channels = SetChannelsByFormat((GX2SurfaceFormat)surf.format);
tex.CompSelR = channels[0];
tex.CompSelG = channels[1];
tex.CompSelB = channels[2];
tex.CompSelA = channels[3];
tex.Regs = new uint[5];
if (surf.compSel.Length != 4)
surf.compSel = new byte[] { 0, 1, 2, 3 };
//Set channels for settings and format
tex.CompSelR = (GX2CompSel)surf.compSel[0];
tex.CompSelG = (GX2CompSel)surf.compSel[1];
tex.CompSelB = (GX2CompSel)surf.compSel[2];
tex.CompSelA = (GX2CompSel)surf.compSel[3];
SetChannelsByFormat((GX2SurfaceFormat)surf.format, tex);
tex.UserData = new ResDict<UserData>();
return tex;
}
@ -590,7 +608,7 @@ namespace Bfres.Structs
case GX2SurfaceFormat.TC_A1_B5_G5_R5_UNorm: return TEX_FORMAT.B5G5R5A1_UNORM;
case GX2SurfaceFormat.TC_R4_G4_B4_A4_UNorm: return TEX_FORMAT.B4G4R4A4_UNORM;
case GX2SurfaceFormat.TCS_R5_G6_B5_UNorm: return TEX_FORMAT.B5G6R5_UNORM;
case GX2SurfaceFormat.TCS_R8_G8_B8_A8_SRGB: return TEX_FORMAT.R8G8B8A8_UNORM;
case GX2SurfaceFormat.TCS_R8_G8_B8_A8_SRGB: return TEX_FORMAT.R8G8B8A8_UNORM_SRGB;
case GX2SurfaceFormat.TCS_R8_G8_B8_A8_UNorm: return TEX_FORMAT.R8G8B8A8_UNORM;
case GX2SurfaceFormat.TCS_R10_G10_B10_A2_UNorm: return TEX_FORMAT.R10G10B10A2_UNORM;
case GX2SurfaceFormat.TC_R11_G11_B10_Float: return TEX_FORMAT.R11G11B10_FLOAT;
@ -605,34 +623,25 @@ namespace Bfres.Structs
throw new Exception($"Cannot convert format {GX2Format}");
}
}
public static GX2CompSel[] SetChannelsByFormat(GX2SurfaceFormat Format)
public static void SetChannelsByFormat(GX2SurfaceFormat Format, Texture tex)
{
GX2CompSel[] channels = new GX2CompSel[4];
switch (Format)
{
case GX2SurfaceFormat.T_BC5_UNorm:
case GX2SurfaceFormat.T_BC5_SNorm:
channels[0] = GX2CompSel.ChannelR;
channels[1] = GX2CompSel.ChannelG;
channels[2] = GX2CompSel.Always0;
channels[3] = GX2CompSel.Always1;
tex.CompSelR = GX2CompSel.ChannelR;
tex.CompSelG = GX2CompSel.ChannelG;
tex.CompSelB = GX2CompSel.Always0;
tex.CompSelA = GX2CompSel.Always1;
break;
case GX2SurfaceFormat.T_BC4_SNorm:
case GX2SurfaceFormat.T_BC4_UNorm:
channels[0] = GX2CompSel.ChannelR;
channels[1] = GX2CompSel.ChannelR;
channels[2] = GX2CompSel.ChannelR;
channels[3] = GX2CompSel.ChannelR;
break;
default:
channels[0] = GX2CompSel.ChannelR;
channels[1] = GX2CompSel.ChannelG;
channels[2] = GX2CompSel.ChannelB;
channels[3] = GX2CompSel.ChannelA;
tex.CompSelR = GX2CompSel.ChannelR;
tex.CompSelG = GX2CompSel.ChannelR;
tex.CompSelB = GX2CompSel.ChannelR;
tex.CompSelA = GX2CompSel.ChannelR;
break;
}
return channels;
}
public void Export(string FileName, bool ExportSurfaceLevel = false,

View file

@ -34,6 +34,11 @@ namespace FirstPlugin
TEX_FORMAT.BC5_SNORM,
TEX_FORMAT.R8G8B8A8_UNORM_SRGB,
TEX_FORMAT.R8G8B8A8_UNORM,
TEX_FORMAT.A8_UNORM,
TEX_FORMAT.R8G8_UNORM,
TEX_FORMAT.B5G6R5_UNORM,
TEX_FORMAT.R10G10B10A2_UNORM,
TEX_FORMAT.B4G4R4A4_UNORM,
};
}
}
@ -45,6 +50,7 @@ namespace FirstPlugin
case TEX_FORMAT.A8_UNORM: return BFLIMFormat.L8_UNORM;
case TEX_FORMAT.R8G8_UNORM: return BFLIMFormat.LA8;
case TEX_FORMAT.B5G6R5_UNORM: return BFLIMFormat.RGB565;
case TEX_FORMAT.B5G5R5A1_UNORM: return BFLIMFormat.RGB5A1;
case TEX_FORMAT.R8G8B8A8_UNORM: return BFLIMFormat.RGBA8;
case TEX_FORMAT.R8G8B8A8_UNORM_SRGB: return BFLIMFormat.RGBA8_SRGB;
case TEX_FORMAT.R10G10B10A2_UNORM: return BFLIMFormat.RGB10A2_UNORM;

View file

@ -851,6 +851,7 @@ namespace FirstPlugin
case TEX_FORMAT.R8_UNORM: return SurfaceFormat.R8_UNORM;
case TEX_FORMAT.R8G8_UNORM: return SurfaceFormat.R8_G8_UNORM;
case TEX_FORMAT.R32G8X24_FLOAT: return SurfaceFormat.R32_G8_X24_FLOAT;
case TEX_FORMAT.B8G8R8X8_UNORM: return SurfaceFormat.B8_G8_R8_A8_UNORM; //Todo
case TEX_FORMAT.ASTC_10x10_SRGB: return SurfaceFormat.ASTC_10x10_SRGB;
case TEX_FORMAT.ASTC_10x10_UNORM: return SurfaceFormat.ASTC_10x10_UNORM;
case TEX_FORMAT.ASTC_10x5_SRGB: return SurfaceFormat.ASTC_10x5_SRGB;

View file

@ -38,10 +38,10 @@ namespace FirstPlugin
public SurfaceDim SurfaceDim = SurfaceDim.Dim2D;
public TileMode TileMode = TileMode.Default;
public Dim Dim = Dim.Dim2D;
public ChannelType RedComp = ChannelType.Red;
public ChannelType GreenComp = ChannelType.Green;
public ChannelType BlueComp = ChannelType.Blue;
public ChannelType AlphaComp = ChannelType.Alpha;
public STChannelType RedComp = STChannelType.Red;
public STChannelType GreenComp = STChannelType.Green;
public STChannelType BlueComp = STChannelType.Blue;
public STChannelType AlphaComp = STChannelType.Alpha;
public TextureData textureData;
public uint TextureLayout;
public uint TextureLayout2 = 0x010007;
@ -70,7 +70,12 @@ namespace FirstPlugin
TexWidth = dds.header.width;
TexHeight = dds.header.height;
var surfaces = DDS.GetArrayFaces(dds, dds.bdata, dds.ArrayCount);
var surfaces = DDS.GetArrayFaces(dds, dds.ArrayCount);
RedComp = dds.RedChannel;
GreenComp = dds.GreenChannel;
BlueComp = dds.BlueChannel;
AlphaComp = dds.AlphaChannel;
foreach (var surface in surfaces)
DataBlockOutput.Add(Utils.CombineByteArray(surface.mipmaps.ToArray()));

View file

@ -30,7 +30,11 @@ namespace FirstPlugin
public uint Swizzle = 0;
public uint MipSwizzle = 0;
public GX2CompSel[] compSel = new GX2CompSel[4];
public STChannelType RedComp = STChannelType.Red;
public STChannelType GreenComp = STChannelType.Green;
public STChannelType BlueComp = STChannelType.Blue;
public STChannelType AlphaComp = STChannelType.Alpha;
public GX2SurfaceDim SurfaceDim = GX2SurfaceDim.Dim2D;
public GX2AAMode AAMode = GX2AAMode.Mode1X;
public float alphaRef = 0.5f;
@ -57,6 +61,11 @@ namespace FirstPlugin
}
DataBlockOutput.Add(dds.bdata);
RedComp = dds.RedChannel;
GreenComp = dds.GreenChannel;
BlueComp = dds.BlueChannel;
AlphaComp = dds.AlphaChannel;
Format = (GX2.GX2SurfaceFormat)FTEX.ConvertToGx2Format(dds.Format);;
}

View file

@ -531,24 +531,32 @@ namespace Switch_Toolbox.Library
HasAlpha = true;
}
Format = GetFormat();
if (!IsDX10 && !IsCompressed) {
Format = GetUncompressedType(IsRGB, HasAlpha, HasLuminance, header.ddspf);
}
reader.TemporarySeek((int)(4 + header.size + DX10HeaderSize), SeekOrigin.Begin);
bdata = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
Format = GetFormat();
Width = header.width;
Height = header.height;
MipCount = header.mipmapCount;
byte[] Components = new byte[4] { 0, 1, 2, 3 };
if (!IsDX10 && !IsCompressed) {
Format = GetUncompressedType(this, Components, IsRGB, HasAlpha, HasLuminance, header.ddspf);
}
RedChannel = (STChannelType)Components[0];
GreenChannel = (STChannelType)Components[1];
BlueChannel = (STChannelType)Components[2];
AlphaChannel = (STChannelType)Components[3];
reader.Dispose();
reader.Close();
MipCount = header.mipmapCount;
Width = header.width;
Height = header.height;
}
private TEX_FORMAT GetUncompressedType(bool IsRGB, bool HasAlpha, bool HasLuminance, Header.DDS_PixelFormat header)
private TEX_FORMAT GetUncompressedType(DDS dds, byte[] Components, bool IsRGB, bool HasAlpha, bool HasLuminance, Header.DDS_PixelFormat header)
{
uint bpp = header.RGBBitCount;
uint RedMask = header.RBitMask;
@ -593,6 +601,7 @@ namespace Switch_Toolbox.Library
{
if (RedMask == R8G8B8_MASKS[0] && GreenMask == R8G8B8_MASKS[1] && BlueMask == R8G8B8_MASKS[2] && AlphaMask == R8G8B8_MASKS[3])
{
dds.bdata = ConvertToRgba(this, "RGB8", 3, new byte[4] { 2, 1, 0, 3 });
return TEX_FORMAT.R8G8B8A8_UNORM;
}
else
@ -608,14 +617,17 @@ namespace Switch_Toolbox.Library
}
else if (RedMask == X8B8G8R8_MASKS[0] && GreenMask == X8B8G8R8_MASKS[1] && BlueMask == X8B8G8R8_MASKS[2] && AlphaMask == X8B8G8R8_MASKS[3])
{
dds.bdata = ConvertToRgba(this, "RGB8X", 4, new byte[4] { 2, 1, 0, 3 });
return TEX_FORMAT.B8G8R8X8_UNORM;
}
else if (RedMask == A8R8G8B8_MASKS[0] && GreenMask == A8R8G8B8_MASKS[1] && BlueMask == A8R8G8B8_MASKS[2] && AlphaMask == A8R8G8B8_MASKS[3])
{
dds.bdata = ConvertBgraToRgba(dds.bdata);
return TEX_FORMAT.R8G8B8A8_UNORM;
}
else if (RedMask == X8R8G8B8_MASKS[0] && GreenMask == X8R8G8B8_MASKS[1] && BlueMask == X8R8G8B8_MASKS[2] && AlphaMask == X8R8G8B8_MASKS[3])
{
dds.bdata = ConvertToRgba(this, "RGB8X", 4, new byte[4] { 0, 1, 2, 3 });
return TEX_FORMAT.B8G8R8X8_UNORM;
}
else
@ -630,6 +642,118 @@ namespace Switch_Toolbox.Library
}
return TEX_FORMAT.UNKNOWN;
}
private static byte[] ConvertRgb8ToRgbx8(byte[] bytes)
{
int size = bytes.Length / 3;
byte[] NewData = new byte[size];
for (int i = 0; i < size; i ++)
{
NewData[4 * i + 0] = bytes[3 * i + 0];
NewData[4 * i + 1] = bytes[3 * i + 1];
NewData[4 * i + 2] = bytes[3 * i + 2];
NewData[4 * i + 3] = 0xFF;
}
return NewData;
}
//Thanks abood. Based on https://github.com/aboood40091/BNTX-Editor/blob/master/formConv.py
private static byte[] ConvertToRgba(DDS dds, string Format, int bpp, byte[] compSel)
{
byte[] bytes = dds.bdata;
if (bytes == null)
throw new Exception("Data block returned null. Make sure the parameters and image properties are correct!");
List<byte[]> mipmaps = new List<byte[]>();
uint Offset = 0;
for (byte a = 0; a < dds.ArrayCount; ++a)
{
for (byte m = 0; m < dds.MipCount; ++m)
{
uint MipWidth = Math.Max(1, dds.Width >> m);
uint MipHeight = Math.Max(1, dds.Height >> m);
uint NewSize = (MipWidth * MipHeight) * 4;
uint OldSize = (MipWidth * MipHeight) * (uint)bpp;
byte[] NewImageData = new byte[NewSize];
mipmaps.Add(NewImageData);
byte[] comp = new byte[4] { 0, 0, 0, 0xFF };
for (int j = 0; j < MipHeight * MipWidth; j++)
{
var pos = Offset + (j * bpp);
var pos_ = (j * 4);
int pixel = 0;
for (int i = 0; i < bpp; i += 1)
pixel |= bytes[pos + i] << (8 * i);
comp = GetComponentsFromPixel(Format, pixel, comp);
NewImageData[pos_ + 3] = comp[compSel[3]];
NewImageData[pos_ + 2] = comp[compSel[2]];
NewImageData[pos_ + 1] = comp[compSel[1]];
NewImageData[pos_ + 0] = comp[compSel[0]];
}
Offset += OldSize;
}
}
return Utils.CombineByteArray(mipmaps.ToArray());
}
private static byte[] GetComponentsFromPixel(string Format, int pixel, byte[] comp)
{
switch (Format)
{
case "RGB8X":
comp[0] = (byte)(pixel & 0xFF);
comp[1] = (byte)((pixel & 0xFF00) >> 8);
comp[2] = (byte)((pixel & 0xFF0000) >> 16);
comp[3] = (byte)(0xFF);
break;
case "RGB8":
comp[0] = (byte)(pixel & 0xFF);
comp[1] = (byte)((pixel & 0xFF00) >> 8);
comp[2] = (byte)((pixel & 0xFF0000) >> 16);
comp[3] = (byte)(0xFF);
break;
case "RGBA4":
comp[0] = (byte)((pixel & 0xF) * 17);
comp[1] = (byte)(((pixel & 0xF0) >> 4) * 17);
comp[2] = (byte)(((pixel & 0xF00) >> 8) * 17);
comp[3] = (byte)(((pixel & 0xF000) >> 12) * 17);
break;
case "RGBA5":
comp[0] = (byte)(((pixel & 0xF800) >> 11) / 0x1F * 0xFF);
comp[1] = (byte)(((pixel & 0x7E0) >> 5) / 0x3F * 0xFF);
comp[2] = (byte)((pixel & 0x1F) / 0x1F * 0xFF);
break;
}
return comp;
}
private static byte[] ConvertBgraToRgba(byte[] bytes)
{
if (bytes == null)
throw new Exception("Data block returned null. Make sure the parameters and image properties are correct!");
for (int i = 0; i < bytes.Length; i += 4)
{
var temp = bytes[i];
bytes[i] = bytes[i + 2];
bytes[i + 2] = temp;
}
return bytes;
}
private void ReadDX10Header(BinaryDataReader reader)
{
DX10header = new DX10Header();
@ -811,6 +935,7 @@ namespace Switch_Toolbox.Library
var Surfaces = new List<STGenericTexture.Surface>();
uint formatSize = GetBytesPerPixel(dds.Format);
bool isBlock = dds.IsCompressed();
if (dds.header.mipmapCount == 0)
dds.header.mipmapCount = 1;

View file

@ -725,14 +725,5 @@ namespace Switch_Toolbox.Library
}
}
}
public static byte[] DecodeBC7(int X, int Y, int block)
{
byte[] result = null;
//Alright so BC7 decompression as multple modes
return result;
}
}
}

View file

@ -202,6 +202,8 @@ namespace Switch_Toolbox.Library
{ TEX_FORMAT.R8G8_B8G8_UNORM, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.B8G8R8X8_UNORM, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.B5G5R5A1_UNORM, new FormatInfo(2, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.B8G8R8A8_UNORM, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.B8G8R8A8_UNORM_SRGB, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R10G10B10A2_UINT, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R10G10B10A2_UNORM, new FormatInfo(4, 1, 1, 1, TargetBuffer.Color) },
@ -457,8 +459,8 @@ namespace Switch_Toolbox.Library
else
{
//If blue channel becomes first, do not swap them!
if (Format.ToString().StartsWith("B") || Format == TEX_FORMAT.B5G6R5_UNORM)
return DDSCompressor.DecodePixelBlock(data, (int)Width, (int)Height, (DDS.DXGI_FORMAT)Format);
// if (Format.ToString().StartsWith("B") || Format == TEX_FORMAT.B5G6R5_UNORM)
// return DDSCompressor.DecodePixelBlock(data, (int)Width, (int)Height, (DDS.DXGI_FORMAT)Format);
if (IsAtscFormat(Format))
return ConvertBgraToRgba(ASTCDecoder.DecodeToRGBA8888(data, (int)GetBlockWidth(Format), (int)GetBlockHeight(Format), 1, (int)Width, (int)Height, 1));
else
@ -812,6 +814,7 @@ namespace Switch_Toolbox.Library
string extension = System.IO.Path.GetExtension(FileName);
return FileName.Substring(0, FileName.Length - extension.Length);
}
private static byte[] ConvertBgraToRgba(byte[] bytes)
{
if (bytes == null)
@ -826,6 +829,71 @@ namespace Switch_Toolbox.Library
return bytes;
}
private static byte[] ConvertBgraToRgba(byte[] bytes, string Format, int bpp, int width, int height, byte[] compSel)
{
if (bytes == null)
throw new Exception("Data block returned null. Make sure the parameters and image properties are correct!");
int size = width * height * 4;
byte[] NewImageData = new byte[size];
byte[] comp = new byte[6] { 0, 0xFF, 0, 0, 0, 0xFF };
for (int y = 0; y < height; y += 1)
{
for (int x = 0; x < width; x += 1)
{
var pos = (y * width + x) * bpp;
var pos_ = (y * width + x) * 4;
int pixel = 0;
for (int i = 0; i < bpp; i += 1)
pixel |= bytes[pos + i] << (8 * i);
comp = GetComponentsFromPixel(Format, pixel, comp);
NewImageData[pos_ + 3] = comp[compSel[3]];
NewImageData[pos_ + 2] = comp[compSel[2]];
NewImageData[pos_ + 1] = comp[compSel[1]];
NewImageData[pos_ + 0] = comp[compSel[0]];
}
}
return NewImageData;
}
private static byte[] GetComponentsFromPixel(string Format, int pixel, byte[] comp)
{
switch (Format)
{
case "RGBX8":
comp[2] = (byte)(pixel & 0xFF);
comp[3] = (byte)((pixel & 0xFF00) >> 8);
comp[4] = (byte)((pixel & 0xFF0000) >> 16);
comp[5] = (byte)((pixel & 0xFF000000) >> 24);
break;
case "RGBA8":
comp[2] = (byte)(pixel & 0xFF);
comp[3] = (byte)((pixel & 0xFF00) >> 8);
comp[4] = (byte)((pixel & 0xFF0000) >> 16);
comp[5] = (byte)((pixel & 0xFF000000) >> 24);
break;
case "RGBA4":
comp[2] = (byte)((pixel & 0xF) * 17);
comp[3] = (byte)(((pixel & 0xF0) >> 4) * 17);
comp[4] = (byte)(((pixel & 0xF00) >> 8) * 17);
comp[5] = (byte)(((pixel & 0xF000) >> 12) * 17);
break;
case "RGBA5":
comp[2] = (byte)(((pixel & 0xF800) >> 11) / 0x1F * 0xFF);
comp[3] = (byte)(((pixel & 0x7E0) >> 5) / 0x3F * 0xFF);
comp[4] = (byte)((pixel & 0x1F) / 0x1F * 0xFF);
break;
}
return comp;
}
public override void Delete()
{
DisposeRenderable();

View file

@ -43,7 +43,7 @@ namespace Switch_Toolbox.Library
public uint[] mipOffset;
public byte[] compSel;
public byte[] compSel = new byte[4] { 0,1,2,3};
public uint[] texRegs;
};