1
0
mirror of synced 2024-12-03 11:37:21 +01:00
Switch-Toolbox/Switch_FileFormatsMain/GUI/TextureUI/TextureImporterSettings.cs

392 lines
14 KiB
C#

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Syroot.NintenTools.NSW.Bntx;
using Syroot.NintenTools.NSW.Bntx.GFX;
using System.Runtime.InteropServices;
using Switch_Toolbox.Library;
using Switch_Toolbox.Library.IO;
namespace FirstPlugin
{
public class TextureImporterSettings
{
public TextureImporterSettings()
{
}
public string TexName;
public uint arrayLength = 1;
public uint AccessFlags = 0x20;
public uint MipCount;
public uint Depth = 1;
public uint TexWidth;
public uint TexHeight;
public uint Flags;
public uint Swizzle;
public uint SampleCount = 1;
public uint Pitch = 32;
public uint[] Regs;
public TEX_FORMAT Format;
public TEX_FORMAT_TYPE FormatType;
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 TextureData textureData;
public uint TextureLayout;
public uint TextureLayout2 = 0x010007;
public uint bpp;
public List<byte[]> DataBlockOutput = new List<byte[]>();
public List<byte[]> DecompressedData = new List<byte[]>();
public BntxFile bntx;
public int sparseResidency = 0; //false
public int sparseBinding = 0; //false
public bool IsSRGB = true;
public bool GenerateMipmaps = false; //If bitmap and count more that 1 then geenrate
public float alphaRef = 0.5f;
public void LoadDDS(string FileName, BntxFile bntxFile, byte[] FileData = null, TextureData tree = null)
{
TexName = Path.GetFileNameWithoutExtension(FileName);
DDS dds = new DDS();
if (FileData != null)
dds.Load(new FileReader(new MemoryStream(FileData)));
else
dds.Load(new FileReader(FileName));
MipCount = dds.header.mipmapCount;
TexWidth = dds.header.width;
TexHeight = dds.header.height;
arrayLength = 1;
if (dds.header.caps2 == (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES)
{
arrayLength = 6;
}
DataBlockOutput.Add(dds.bdata);
var formats = dds.GetFormat();
Format = formats.Item1;
FormatType = formats.Item2;
Texture tex = FromBitMap(DataBlockOutput[0], this);
if (tree != null)
{
tree.LoadTexture(tex, 1);
}
else
{
textureData = new TextureData(tex, bntxFile);
}
}
public void LoadTGA(string FileName, BntxFile bntxFile)
{
DecompressedData.Clear();
TexName = Path.GetFileNameWithoutExtension(FileName);
bntx = bntxFile;
Format = TEX_FORMAT.BC1;
FormatType = TEX_FORMAT_TYPE.SRGB;
GenerateMipmaps = true;
Bitmap Image = Paloma.TargaImage.LoadTargaImage(FileName);
Image = STGenericTexture.SwapBlueRedChannels(Image);
TexWidth = (uint)Image.Width;
TexHeight = (uint)Image.Height;
MipCount = (uint)GetTotalMipCount();
DecompressedData.Add(BitmapExtension.ImageToByte(Image));
Image.Dispose();
if (DecompressedData.Count == 0)
{
throw new Exception("Failed to load " + Format);
}
}
public void LoadBitMap(string FileName, BntxFile bntxFile)
{
DecompressedData.Clear();
TexName = Path.GetFileNameWithoutExtension(FileName);
bntx = bntxFile;
Format = TEX_FORMAT.BC1;
FormatType = TEX_FORMAT_TYPE.SRGB;
GenerateMipmaps = true;
Bitmap Image = new Bitmap(FileName);
Image = STGenericTexture.SwapBlueRedChannels(Image);
TexWidth = (uint)Image.Width;
TexHeight = (uint)Image.Height;
MipCount = (uint)GetTotalMipCount();
DecompressedData.Add(BitmapExtension.ImageToByte(Image));
Image.Dispose();
if (DecompressedData.Count == 0)
{
throw new Exception("Failed to load " + Format);
}
}
public int GetTotalMipCount()
{
int MipmapNum = 0;
uint num = Math.Max(TexHeight, TexWidth);
int width = (int)TexWidth;
int height = (int)TexHeight;
while (true)
{
num >>= 1;
width = width / 2;
height = height / 2;
if (width <= 0 || height <= 0)
break;
if (num > 0)
++MipmapNum;
else
break;
}
return MipmapNum;
}
public byte[] GenerateMips(int SurfaceLevel = 0)
{
Bitmap Image = BitmapExtension.GetBitmap(DecompressedData[SurfaceLevel], (int)TexWidth, (int)TexHeight);
List<byte[]> mipmaps = new List<byte[]>();
mipmaps.Add(STGenericTexture.CompressBlock(DecompressedData[SurfaceLevel], (int)TexWidth, (int)TexHeight, Format, FormatType, alphaRef));
//while (Image.Width / 2 > 0 && Image.Height / 2 > 0)
// for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
{
Image = BitmapExtension.Resize(Image, Image.Width / 2, Image.Height / 2);
mipmaps.Add(STGenericTexture.CompressBlock(BitmapExtension.ImageToByte(Image), Image.Width, Image.Height, Format, FormatType, alphaRef));
}
Image.Dispose();
return Utils.CombineByteArray(mipmaps.ToArray());
}
public void Compress()
{
DataBlockOutput.Clear();
foreach (var surface in DecompressedData)
{
DataBlockOutput.Add(STGenericTexture.CompressBlock(surface, (int)TexWidth, (int)TexHeight, Format, FormatType, alphaRef));
}
}
public static uint DIV_ROUND_UP(uint value1, uint value2)
{
return TegraX1Swizzle.DIV_ROUND_UP(value1, value2);
}
public Texture FromBitMap(byte[] data, TextureImporterSettings settings)
{
Texture tex = new Texture();
tex.Height = (uint)settings.TexHeight;
tex.Width = (uint)settings.TexWidth;
var formats = TextureData.GetSurfaceFormat(settings.Format, settings.FormatType);
tex.Format = formats.Item1;
tex.FormatType = formats.Item2;
tex.Name = settings.TexName;
tex.Path = "";
tex.TextureData = new List<List<byte[]>>();
if (settings.MipCount == 0)
settings.MipCount = 1;
STChannelType[] channels = STGenericTexture.SetChannelsByFormat(settings.Format);
tex.ChannelRed = (ChannelType)channels[0];
tex.ChannelGreen = (ChannelType)channels[1];
tex.ChannelBlue = (ChannelType)channels[2];
tex.ChannelAlpha = (ChannelType)channels[3];
tex.sparseBinding = settings.sparseBinding;
tex.sparseResidency = settings.sparseResidency;
tex.AccessFlags = settings.AccessFlags;
tex.ArrayLength = settings.arrayLength;
tex.MipCount = settings.MipCount;
tex.Depth = settings.Depth;
tex.Dim = settings.Dim;
tex.Flags = settings.Flags;
tex.TileMode = settings.TileMode;
tex.textureLayout = settings.TextureLayout;
tex.textureLayout2 = settings.TextureLayout2;
tex.Swizzle = settings.Swizzle;
tex.SurfaceDim = settings.SurfaceDim;
tex.SampleCount = settings.SampleCount;
tex.Regs = settings.Regs;
tex.Pitch = settings.Pitch;
tex.MipOffsets = new long[tex.MipCount];
List<byte[]> arrayFaces = new List<byte[]>();
if (tex.ArrayLength > 1)
arrayFaces = DDS.GetArrayFaces(data, tex.ArrayLength);
else
arrayFaces.Add(data);
for (int i = 0; i < tex.ArrayLength; i++)
{
List<byte[]> mipmaps = SwizzleSurfaceMipMaps(tex, arrayFaces[i], tex.TileMode);
tex.TextureData.Add(mipmaps);
byte[] test = Combine(mipmaps);
tex.TextureData[i][0] = test;
}
return tex;
}
public static List<byte[]> SwizzleSurfaceMipMaps(FTEX tex, byte[] data)
{
throw new Exception("Unimplemented");
}
public static List<byte[]> SwizzleSurfaceMipMaps(Texture tex,byte[] data, TileMode TileMode)
{
int blockHeightShift = 0;
int target = 1;
uint Pitch = 0;
uint SurfaceSize = 0;
uint blockHeight = 0;
uint blk_dim = Formats.blk_dims((uint)((int)tex.Format >> 8));
uint blkWidth = blk_dim >> 4;
uint blkHeight = blk_dim & 0xF;
uint linesPerBlockHeight = 0;
uint bpp = Formats.bpps((uint)((int)tex.Format >> 8));
if ((int)TileMode == 1)
{
blockHeight = 1;
tex.BlockHeightLog2 = 0;
tex.Alignment = 1;
linesPerBlockHeight = 1;
tex.ReadTextureLayout = 0;
}
else
{
blockHeight = TegraX1Swizzle.GetBlockHeight(DIV_ROUND_UP(tex.Height, blkHeight));
tex.BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1;
Console.WriteLine("BlockHeightLog2 " + tex.BlockHeightLog2);
Console.WriteLine("blockHeight " + blockHeight);
tex.Alignment = 512;
tex.ReadTextureLayout = 1;
linesPerBlockHeight = blockHeight * 8;
}
List<byte[]> mipmaps = new List<byte[]>();
for (int mipLevel = 0; mipLevel < tex.MipCount; mipLevel++)
{
var result = TextureHelper.GetCurrentMipSize(tex.Width, tex.Height, blkWidth, blkHeight, bpp, mipLevel);
uint offset = result.Item1;
uint size = result.Item2;
byte[] data_ = Utils.SubArray(data, offset, size);
uint width_ = Math.Max(1, tex.Width >> mipLevel);
uint height_ = Math.Max(1, tex.Height >> mipLevel);
uint width__ = DIV_ROUND_UP(width_, blkWidth);
uint height__ = DIV_ROUND_UP(height_, blkHeight);
byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, (uint)tex.Alignment) - SurfaceSize)];
SurfaceSize += (uint)AlignedData.Length;
Console.WriteLine("SurfaceSize Aligned " + AlignedData);
Console.WriteLine("MipOffsets " + SurfaceSize);
tex.MipOffsets[mipLevel] = SurfaceSize;
if (tex.TileMode == TileMode.LinearAligned)
{
Pitch = width__ * bpp;
Console.WriteLine("Pitch 1 " + Pitch);
if (target == 1)
{
Pitch = TegraX1Swizzle.round_up(width__ * bpp, 32);
Console.WriteLine("Pitch 2 " + Pitch);
}
SurfaceSize += Pitch * height__;
}
else
{
if (TegraX1Swizzle.pow2_round_up(height__) < linesPerBlockHeight)
blockHeightShift += 1;
Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64);
Console.WriteLine("Pitch 1 " + Pitch);
Console.WriteLine("blockHeightShift " + blockHeightShift);
SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8);
Console.WriteLine("SurfaceSize " + SurfaceSize);
byte[] SwizzledData = TegraX1Swizzle.swizzle(width_, height_, blkWidth, blkHeight, target, bpp, (uint)tex.TileMode, (int)Math.Max(0, tex.BlockHeightLog2 - blockHeightShift), data_);
mipmaps.Add(AlignedData.Concat(SwizzledData).ToArray());
}
}
tex.ImageSize = SurfaceSize;
return mipmaps;
}
private byte[] Combine(List<byte[]> arrays)
{
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (byte[] array in arrays)
{
System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
private void button1_Click(object sender, EventArgs e)
{
if (DataBlockOutput != null)
{
Texture tex = FromBitMap(DataBlockOutput[0], this);
if (textureData != null)
{
textureData.LoadTexture(tex, 1);
}
else
{
textureData = new TextureData(tex, bntx);
}
}
else
{
MessageBox.Show("Something went wrong???");
}
}
}
}