Rework IGZ reading and add writing back (for textures)

This commit is contained in:
KillzXGaming 2019-08-05 15:38:03 -04:00
parent aa92482f15
commit a655ea24d7
12 changed files with 581 additions and 306 deletions

Binary file not shown.

View file

@ -18,7 +18,7 @@ using OpenTK;
namespace FirstPlugin namespace FirstPlugin
{ {
public class BMD : TreeNodeFile, IFileFormat, IContextMenuNode, ITextureContainer public class BMD : TreeNodeFile, IFileFormat, IContextMenuNode
{ {
public FileType FileType { get; set; } = FileType.Layout; public FileType FileType { get; set; } = FileType.Layout;
@ -64,8 +64,6 @@ namespace FirstPlugin
} }
} }
public Dictionary<string, STGenericTexture> Textures { get; set; }
bool DrawablesLoaded = false; bool DrawablesLoaded = false;
public override void OnClick(TreeView treeView) public override void OnClick(TreeView treeView)
{ {
@ -114,10 +112,6 @@ namespace FirstPlugin
DrawableContainer.Drawables.Add(Renderer); DrawableContainer.Drawables.Add(Renderer);
DrawableContainer.Drawables.Add(Skeleton); DrawableContainer.Drawables.Add(Skeleton);
Textures = new Dictionary<string, STGenericTexture>();
BMD_Renderer.TextureContainers.Add(this);
BMDFile = Model.Load(stream); BMDFile = Model.Load(stream);
LoadBMD(BMDFile); LoadBMD(BMDFile);
} }

View file

@ -96,9 +96,13 @@ namespace FirstPlugin
//Remove this stupid long pointless path //Remove this stupid long pointless path
file.FileName = file.FileName.Replace("temporary/octane/data/nx/output/", string.Empty); file.FileName = file.FileName.Replace("temporary/octane/data/nx/output/", string.Empty);
file.FileName = file.FileName.Replace("temporary/mack/data/win64/output/", string.Empty);
file.FileName = file.FileName.Replace("temporary/mack/data/nx/output/", string.Empty);
// if (file.FileOffset >= 0xff000000)
// file.FileOffset =
// if (file.FileOffset >= 0xff000000)
// file.FileOffset =
} }
@ -147,6 +151,9 @@ namespace FirstPlugin
{ {
get get
{ {
if (FileOffset == 0)
return new byte[0];
using (var reader = new FileReader(SourceFile)) using (var reader = new FileReader(SourceFile))
{ {
int size = 0; int size = 0;
@ -181,6 +188,7 @@ namespace FirstPlugin
} }
else else
{ {
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
return reader.ReadBytes((int)DecompressedFileSize); return reader.ReadBytes((int)DecompressedFileSize);
} }
} }

View file

@ -1,295 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
namespace FirstPlugin
{
public class IGZ : STGenericTexture, IFileFormat, ISingleTextureIconLoader
{
public STGenericTexture IconTexture { get { return this; } }
public FileType FileType { get; set; } = FileType.Layout;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Crash N.Sane Trilogy / CTR: Nitro-Fueled (IGZ)" };
public string[] Extension { get; set; } = new string[] { "*.igz" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
return reader.CheckSignature(4, "\x01ZGI");
}
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public Dictionary<uint, FormatInfo> Formats = new Dictionary<uint, FormatInfo>()
{
/* { 0xDE, new FormatInfo(TEX_FORMAT.R8G8B8A8_UNORM) },
{ 0x08, new FormatInfo(TEX_FORMAT.R8G8B8A8_UNORM) },
{ 0x46, new FormatInfo(TEX_FORMAT.R8G8B8A8_UNORM) },
{ 0x99, new FormatInfo(TEX_FORMAT.R8G8B8A8_UNORM) },
// { 0xCD, new FormatInfo(TEX_FORMAT.BC1_UNORM) },
{ 0x06, new FormatInfo(TEX_FORMAT.BC1_UNORM) },
{ 0x3B, new FormatInfo(TEX_FORMAT.BC1_UNORM) },
{ 0x9D, new FormatInfo(TEX_FORMAT.BC1_UNORM) },
{ 0x51, new FormatInfo(TEX_FORMAT.BC1_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x28, new FormatInfo(TEX_FORMAT.BC1_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x1B, new FormatInfo(TEX_FORMAT.BC1_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x39, new FormatInfo(TEX_FORMAT.BC3_UNORM) },
{ 0x88, new FormatInfo(TEX_FORMAT.BC3_UNORM) },
{ 0xDA, new FormatInfo(TEX_FORMAT.BC3_UNORM) },
{ 0xCD, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x6E, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x45, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x37, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x18, new FormatInfo(TEX_FORMAT.BC5_UNORM) },
{ 0x47, new FormatInfo(TEX_FORMAT.BC5_UNORM) },
{ 0xB9, new FormatInfo(TEX_FORMAT.BC5_UNORM) },
{ 0x78, new FormatInfo(TEX_FORMAT.BC5_UNORM) },
*/
{ 0x9D3B06CD, new FormatInfo(TEX_FORMAT.BC1_UNORM) },
{ 0xDA888839, new FormatInfo(TEX_FORMAT.BC3_UNORM) }, //PC
{ 0x78B94718, new FormatInfo(TEX_FORMAT.BC5_UNORM) }, //PC
{ 0x994608DE, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT) }, //PC
{ 0x1B282851, new FormatInfo(TEX_FORMAT.BC1_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x37456ECD, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0xD0124568, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Switch) },
{ 0x8EBE8CF2, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT, PlatformSwizzle.Platform_Switch) },
{ 0xF8313483, new FormatInfo(TEX_FORMAT.BC1_UNORM, PlatformSwizzle.Platform_Ps4) },
{ 0xF0B976CF, new FormatInfo(TEX_FORMAT.BC3_UNORM, PlatformSwizzle.Platform_Ps4) },
{ 0x7D081E6A, new FormatInfo(TEX_FORMAT.BC5_UNORM, PlatformSwizzle.Platform_Ps4) },
{ 0x9B54FB48, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT, PlatformSwizzle.Platform_Ps4) },
{ 0xEDF22608, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT, PlatformSwizzle.Platform_Ps4) }, //Todo BGR32
};
public class FormatInfo
{
public TEX_FORMAT Format;
public PlatformSwizzle Platform;
public FormatInfo(TEX_FORMAT format, PlatformSwizzle platform = PlatformSwizzle.None)
{
Format = format;
Platform = platform;
}
}
public void Load(System.IO.Stream stream)
{
using (var reader = new FileReader(stream))
{
reader.ReadSignature(4, "\x01ZGI");
uint unknown = reader.ReadUInt32(); //Same as section count?
uint unknown2 = reader.ReadUInt32(); //2171947023
uint unknown3 = reader.ReadUInt32(); //2
uint SectionCount = reader.ReadUInt32();
reader.Seek(4); //padding
//Always 3 of these used that point to certain areas
const int BLOCK_COUNT = 3;
uint[] offsets = new uint[BLOCK_COUNT];
uint[] sizes = new uint[BLOCK_COUNT];
for (int j = 0; j < BLOCK_COUNT; j++)
{
offsets[j] = reader.ReadUInt32();
sizes[j] = reader.ReadUInt32();
reader.Seek(8);
}
List<string> TextureNames = new List<string>();
FormatInfo TextureFormat = null;
//Now go to the first block. This is a list of section headers
//Each header follows the same structure, a signature, count, and size
reader.SeekBegin(offsets[0]);
for (int s = 0; s < SectionCount; s++)
{
long pos = reader.Position;
string signature = reader.ReadString(4);
uint count = reader.ReadUInt32();
uint sectioSize = reader.ReadUInt32();
uint dataOffset = reader.ReadUInt32(); //0x10. Relative to start of section
Console.WriteLine($"{signature} {count} {sectioSize} {dataOffset}");
reader.SeekBegin(pos + dataOffset);
switch (signature)
{
case "TSTR":
for (int i = 0; i < count; i++)
TextureNames.Add(reader.ReadZeroTerminatedString());
if (count > 0)
Text = TextureNames[0];
foreach (string name in TextureNames)
Console.WriteLine("tex " + name);
break;
case "TMET":
break;
case "MTSZ":
break;
case "EXID": //Texture Formats and maybe other formats
// reader.ReadUInt32(); //padding?
//Seems only one code is used but why?
uint FormatCode = reader.ReadUInt32();
if (Formats.ContainsKey(FormatCode))
TextureFormat = Formats[FormatCode];
else
throw new Exception("Unsupported format code!" + FormatCode.ToString("X"));
Console.WriteLine($"TextureFormat {FormatCode.ToString("X")}");
break;
case "RVTB":
break;
case "RSTT":
break;
case "ROFS":
break;
case "REXT":
break;
case "ROOT":
break;
case "ONAM":
break;
default:
Console.WriteLine("Unexpected Magic " + signature);
break;
}
reader.SeekBegin(pos + sectioSize);
}
reader.SeekBegin(offsets[1] + 0x48);
ushort width = reader.ReadUInt16();
ushort height = reader.ReadUInt16();
ushort depth = reader.ReadUInt16();
ushort mipCount = reader.ReadUInt16();
ushort arrayCount = reader.ReadUInt16();
reader.Seek(10); //padding
uint unk = reader.ReadUInt32();
reader.Seek(8); //padding
uint ImageSize = reader.ReadUInt32();
//Seek to start of image block
reader.Seek(84);
long dataPos = reader.Position;
long ImageSizeReal = reader.BaseStream.Length - dataPos;
ImageData = reader.ReadBytes((int)ImageSizeReal);
Width = width;
Height = height;
Depth = depth;
ArrayCount = arrayCount;
Format = TextureFormat.Format;
// PlatformSwizzle = TextureFormat.Platform;
Console.WriteLine($"PlatformSwizzle " + PlatformSwizzle);
}
}
public byte[] ImageData { get; set; }
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.BC1_UNORM,
TEX_FORMAT.BC3_UNORM,
TEX_FORMAT.BC5_UNORM,
TEX_FORMAT.R8G8B8A8_UNORM,
TEX_FORMAT.R32G32B32A32_FLOAT,
};
}
}
public override bool CanEdit { get; set; } = false;
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
{
}
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
if (PlatformSwizzle == PlatformSwizzle.Platform_Switch)
return TegraX1Swizzle.GetImageData(this, ImageData, ArrayLevel, MipLevel, 1);
else
return ImageData;
}
public override void OnClick(TreeView treeView)
{
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
editor.LoadProperties(GenericProperties);
editor.LoadImage(this);
}
public void Unload()
{
}
public byte[] Save()
{
return null;
}
public class TSTR
{
List<string> TextureNames = new List<string>();
public void Read(FileReader reader)
{
long pos = reader.Position;
reader.ReadSignature(4, "TSTR");
uint textureCount = reader.ReadUInt32();
uint sectionSize = reader.ReadUInt32();
uint stringOffset = reader.ReadUInt32();
reader.SeekBegin(pos +stringOffset);
for (int i = 0; i < textureCount; i++)
{
TextureNames.Add(reader.ReadZeroTerminatedString());
}
}
}
}
}

View file

@ -0,0 +1,401 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
namespace FirstPlugin
{
//A structure for an IGZ file that contains multiple resources
//This is to fully parse and get data from it from all resource types
//This links to multiple seperate files
public class IGZ_Structure
{
public static bool Identify(System.IO.Stream stream)
{
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
{
return reader.CheckSignature(4, "\x01ZGI");
}
}
public enum Platform
{
Ps4,
Switch,
PC,
}
//PC works perfectly, but Switch has issues with CTR
//Also a note, switch swizzling is never used? It always seems to be raw data
//Set the platform still for the sake of it. It won't swizzle or anything
public Dictionary<uint, FormatInfo> Formats = new Dictionary<uint, FormatInfo>()
{
{ 0x9D3B06CD, new FormatInfo(TEX_FORMAT.BC1_UNORM) },
{ 0xDA888839, new FormatInfo(TEX_FORMAT.BC3_UNORM) }, //PC
{ 0x78B94718, new FormatInfo(TEX_FORMAT.BC5_UNORM) }, //PC
{ 0x994608DE, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT) }, //PC
{ 0x1B282851, new FormatInfo(TEX_FORMAT.BC1_UNORM, Platform.Switch) },
{ 0x37456ECD, new FormatInfo(TEX_FORMAT.BC3_UNORM, Platform.Switch) },
{ 0xD0124568, new FormatInfo(TEX_FORMAT.BC3_UNORM, Platform.Switch) },
{ 0x8EBE8CF2, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT, Platform.Switch) },
{ 0xF8313483, new FormatInfo(TEX_FORMAT.BC1_UNORM, Platform.Ps4) },
{ 0xF0B976CF, new FormatInfo(TEX_FORMAT.BC3_UNORM, Platform.Ps4) },
{ 0x7D081E6A, new FormatInfo(TEX_FORMAT.BC5_UNORM, Platform.Ps4) },
{ 0x9B54FB48, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT, Platform.Ps4) },
{ 0xEDF22608, new FormatInfo(TEX_FORMAT.R32G32B32_FLOAT, Platform.Ps4) }, //Todo BGR32
};
public class FormatInfo
{
public TEX_FORMAT Format;
public Platform Platform;
public FormatInfo(TEX_FORMAT format, Platform platform = Platform.PC)
{
Format = format;
Platform = platform;
}
}
public uint Version { get; set; }
public uint HeaderUnknown { get; set; }
public uint HeaderUnknown2 { get; set; }
public List<string> HeaderStrings = new List<string>();
public List<string> DependenciesTable = new List<string>();
public List<string> StringTable = new List<string>();
public List<string> TMETStrings = new List<string>();
public List<uint> MTSZTable = new List<uint>();
public List<Tuple<uint, uint>> FormatCodeList = new List<Tuple<uint, uint>>();
public List<uint> ONAMTable = new List<uint>();
public List<CommonHeaderInfo> Headers = new List<CommonHeaderInfo>();
public TextureBlockInfo TextureInfo;
public byte[] UnknownData;
public void Read(FileReader reader)
{
reader.ReadSignature(4, "\x01ZGI");
Version = reader.ReadUInt32(); //10
HeaderUnknown = reader.ReadUInt32(); //2171947023
HeaderUnknown2 = reader.ReadUInt32(); //2
uint SectionCount = reader.ReadUInt32();
reader.Seek(4); //padding
//A chunk/block offset list.
List<uint> offsets = new List<uint>();
List<uint> sizes = new List<uint>();
while (true)
{
uint offset = reader.ReadUInt32();
uint size = reader.ReadUInt32();
uint unknown = reader.ReadUInt32();
uint unknown2 = reader.ReadUInt32();
if (offset != 0)
{
offsets.Add(offset);
sizes.Add(size);
}
else
break;
}
//After we parsed the offsets/size array
//Save the rest of the data up to the next section
//All of this is mostly padding and a string or 2
reader.Seek(-16); //Seek back 16 due to trying to read the chunk info
long headerEnd = reader.Position;
UnknownData = reader.ReadBytes((int)(offsets[0] - headerEnd));
//Now go to the first block. This is a list of section headers
//Each header follows the same structure, a signature, count, and size
reader.SeekBegin(offsets[0]);
for (int s = 0; s < SectionCount; s++)
{
long pos = reader.Position;
string signature = reader.ReadString(4);
uint count = reader.ReadUInt32();
uint sectioSize = reader.ReadUInt32();
uint dataOffset = reader.ReadUInt32(); //0x10. Relative to start of section
Console.WriteLine($"{signature} {count} {sectioSize} {dataOffset}");
CommonHeaderInfo header = new CommonHeaderInfo();
header.Magic = signature;
reader.SeekBegin(pos + dataOffset);
switch (signature)
{
case "TDEP": //Dependinces table
for (int i = 0; i < count; i++)
DependenciesTable.Add(reader.ReadZeroTerminatedString());
break;
case "TSTR": //string table i assume
for (int i = 0; i < count; i++)
StringTable.Add(reader.ReadZeroTerminatedString());
break;
case "TMET": //Another string list
for (int i = 0; i < count; i++)
TMETStrings.Add(reader.ReadZeroTerminatedString());
break;
case "MTSZ":
for (int i = 0; i < count; i++)
MTSZTable.Add(reader.ReadUInt32());
break;
case "EXID": //A format list for multiple data types
for (int i = 0; i < count; i++)
FormatCodeList.Add(Tuple.Create(reader.ReadUInt32(), reader.ReadUInt32()));
break;
case "EXNM": //Material data
break;
case "RVTB":
break;
case "RSTT":
break;
case "ROFS":
break;
case "REXT":
break;
case "ROOT":
break;
case "ONAM":
for (int i = 0; i < count; i++)
ONAMTable.Add(reader.ReadUInt32());
break;
default:
Console.WriteLine("Unexpected Magic " + signature);
break;
}
//For saving back just save the raw bytes
reader.SeekBegin(pos);
header.data = reader.ReadBytes((int)sectioSize);
Headers.Add(header);
reader.SeekBegin(pos + sectioSize);
}
//Todo find a better check for how a block/chunk is determined
if (sizes[1] == 192) //The size of an image info chunk/block
{
reader.SeekBegin(offsets[1]);
TextureInfo = new TextureBlockInfo();
TextureInfo.UnkownData1 = reader.ReadBytes(0x48);
TextureInfo.Width = reader.ReadUInt16();
TextureInfo.Height = reader.ReadUInt16();
TextureInfo.Depth = reader.ReadUInt16();
TextureInfo.MipCount = reader.ReadUInt16();
TextureInfo.ArrayCount = reader.ReadUInt16();
reader.Seek(10); //padding
TextureInfo.UnknownValue = reader.ReadUInt32();
reader.Seek(8); //padding
uint ImageSize = reader.ReadUInt32();
//Seek to start of image block
TextureInfo.UnkownData2 = reader.ReadBytes((int)(offsets[2] - reader.Position));
//Seek the second block/chunk info
reader.SeekBegin(offsets[2]);
long dataPos = reader.Position;
//The imagesize is weird so get from the end of file
long ImageSizeReal = reader.BaseStream.Length - dataPos;
TextureInfo.ImageData = reader.ReadBytes((int)ImageSizeReal);
//Todo why is there 2 format codes even for textures?
foreach (var format in FormatCodeList)
{
if (Formats.ContainsKey(format.Item1))
TextureInfo.FormatInfo = Formats[format.Item1];
else
Console.WriteLine("Unsupported format code!" + format.Item1.ToString("X"));
/* if (Formats.ContainsKey(format.Item2))
TextureInfo.FormatInfo = Formats[format.Item2];
else
Console.WriteLine("Unsupported format code!" + format.Item2.ToString("X"));*/
}
}
else if (sizes[1] == 2568) //The size of a model info chunk/block
{
}
}
//Todo this has quite a bit of unknowns and needs more chunk support
//Textures should save fine
public void Write(FileWriter writer)
{
if (TextureInfo == null)
throw new Exception("Only textures can be saved currently!");
//Set the format code for the texture if found a proper pair match
if (TextureInfo != null)
{
//Go through each value and find a pair with a matching format and matching platform
foreach (var formatInfo in Formats)
{
uint code = formatInfo.Key;
if (formatInfo.Value.Format == TextureInfo.FormatInfo.Format &&
formatInfo.Value.Platform == TextureInfo.FormatInfo.Platform)
{
//Set the first code
//unsure what the second code is for
uint code2 = FormatCodeList[0].Item2;
FormatCodeList[0] = Tuple.Create(code, code2);
}
}
}
writer.SetByteOrder(false);
writer.WriteSignature("\x01ZGI");
writer.Write(Version);
writer.Write(HeaderUnknown);
writer.Write(HeaderUnknown2);
writer.Write(Headers.Count);
writer.Seek(4); //padding
long chunkInfoArray = writer.Position;
//Reseve space for all the used chunks
for (int i = 0; i < 3; i++)
{
writer.Write(uint.MaxValue);
writer.Write(uint.MaxValue);
writer.Write(uint.MaxValue);
writer.Write(uint.MaxValue);
}
//Possibly aligned data, but there's sometimes strings in it
writer.Write(UnknownData);
//Now start saving the header chunk.
long headerArrayPos = writer.Position;
foreach (var header in Headers)
{
if (header.Magic == "TSTR") //Save our string array chunk
{
long posTSRT = writer.Position;
writer.WriteSignature("TSTR");
writer.Write(StringTable.Count);
long posStrSizeOfs = writer.Position;
writer.Write(0); //save size after
writer.Write(16); //offset
foreach (var item in StringTable)
{
writer.WriteString(item);
}
long posTSRTEnd = writer.Position;
//Note i will automate sizes later
writer.SeekBegin(posStrSizeOfs);
writer.Write((uint)(posTSRTEnd - posTSRT));
writer.SeekBegin(posTSRTEnd);
}
else if (header.Magic == "EXID") //Save our format chunk
{
writer.WriteSignature("EXID");
writer.Write(FormatCodeList.Count);
writer.Write(20 + (FormatCodeList.Count * 8)); //Size
writer.Write(20); //Offset
writer.Write(0); //Padding
foreach (var item in FormatCodeList)
{
writer.Write(item.Item1);
writer.Write(item.Item2);
}
}
else
writer.Write(header.data);
}
long headerEndPos = writer.Position;
long infoChunkPos = writer.Position;
if (TextureInfo != null)
{
writer.Write(TextureInfo.UnkownData1);
writer.Write(TextureInfo.Width);
writer.Write(TextureInfo.Height);
writer.Write(TextureInfo.Depth);
writer.Write(TextureInfo.MipCount);
writer.Write(TextureInfo.ArrayCount);
writer.Seek(10); //padding
writer.Write(TextureInfo.UnknownValue);
writer.Seek(8); //padding
writer.Write(TextureInfo.ImageData.Length);
writer.Write(TextureInfo.UnkownData2);
}
long infoChunkEndPos = writer.Position;
long dataChunkPos = writer.Position;
if (TextureInfo != null)
{
writer.Write(TextureInfo.ImageData);
}
long dataChunkEndPos = writer.Position;
//Go back and write all the used chunk data so far
writer.SeekBegin(chunkInfoArray);
//Write the header array chunk first
writer.Write((uint)headerArrayPos); //Offset
writer.Write((uint)(headerEndPos - headerArrayPos)); //Size
writer.Write(2048); //Unknown
writer.Write(0); //Unknown
//Write the info chunk
writer.Write((uint)infoChunkPos); //Offset
writer.Write((uint)(infoChunkEndPos - infoChunkPos)); //Size
writer.Write(8); //Unknown
writer.Write(131072); //Unknown
//Write the data chunk
writer.Write((uint)dataChunkPos); //Offset
writer.Write((uint)(dataChunkEndPos - dataChunkPos)); //Size
writer.Write(4); //Unknown
writer.Write(0); //Unknown
}
public class CommonHeaderInfo
{
public string Magic;
public byte[] data;
}
public class TextureBlockInfo
{
public byte[] UnkownData1;
public uint UnknownValue;
public byte[] UnkownData2;
public byte[] ImageData { get; set; }
public ushort Width { get; set; }
public ushort Height { get; set; }
public ushort Depth { get; set; }
public ushort MipCount { get; set; }
public ushort ArrayCount { get; set; }
public FormatInfo FormatInfo { get; set; }
}
}
}

View file

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Toolbox;
using System.Windows.Forms;
using Toolbox.Library;
using Toolbox.Library.IO;
using Toolbox.Library.Forms;
namespace FirstPlugin
{
//I keep textures seperate due to the way files are handled
//While i could store all section data in one file, it's better to keep textures as
//a single tree node as all model sections are usually empty
public class IGZ_TEX : STGenericTexture, IFileFormat, ISingleTextureIconLoader, IContextMenuNode
{
public STGenericTexture IconTexture { get { return this; } }
public FileType FileType { get; set; } = FileType.Layout;
public bool CanSave { get; set; }
public string[] Description { get; set; } = new string[] { "Crash N.Sane Trilogy / CTR: Nitro-Fueled (IGZ)" };
public string[] Extension { get; set; } = new string[] { "*.igz" };
public string FileName { get; set; }
public string FilePath { get; set; }
public IFileInfo IFileInfo { get; set; }
public bool Identify(System.IO.Stream stream)
{
return IGZ_Structure.Identify(stream);
}
public Type[] Types
{
get
{
List<Type> types = new List<Type>();
return types.ToArray();
}
}
public ToolStripItem[] GetContextMenuItems()
{
List<ToolStripItem> Items = new List<ToolStripItem>();
Items.Add(new ToolStripMenuItem("Save", null, SaveAction, Keys.Control | Keys.S));
Items.AddRange(base.GetContextMenuItems());
return Items.ToArray();
}
private void SaveAction(object sender, EventArgs args)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = Utils.GetAllFilters(this);
sfd.FileName = FileName;
if (sfd.ShowDialog() == DialogResult.OK)
{
STFileSaver.SaveFileFormat(this, sfd.FileName);
}
}
public IGZ_Structure IGZStructure;
public IGZ_Structure.Platform PlatformFormat;
public void Load(System.IO.Stream stream)
{
CanSave = true;
using (var reader = new FileReader(stream))
{
//Parse with the IGZ structure class and get the texture info block
IGZStructure = new IGZ_Structure();
IGZStructure.Read(reader);
//Set all the info from the parsed struct
var texInfo = IGZStructure.TextureInfo;
Width = texInfo.Width;
Height = texInfo.Height;
Format = texInfo.FormatInfo.Format;
PlatformFormat = texInfo.FormatInfo.Platform;
ArrayCount = texInfo.ArrayCount;
Depth = texInfo.Depth;
//Don't set the platform swizzle because they don't seem to be swizzled?
// PlatformSwizzle = texInfo.FormatInfo.Platform;
//Grab the first entry from the string table
if (IGZStructure.StringTable.Count > 0)
Text = IGZStructure.StringTable[0];
else
Text = FileName;
}
}
public override TEX_FORMAT[] SupportedFormats
{
get
{
return new TEX_FORMAT[]
{
TEX_FORMAT.BC1_UNORM,
TEX_FORMAT.BC3_UNORM,
TEX_FORMAT.BC5_UNORM,
TEX_FORMAT.R8G8B8A8_UNORM,
TEX_FORMAT.R32G32B32A32_FLOAT,
};
}
}
public override bool CanEdit { get; set; } = true;
public override void SetImageData(System.Drawing.Bitmap bitmap, int ArrayLevel)
{
Console.WriteLine("Setting ImageData");
IGZStructure.TextureInfo.ImageData = GenerateMipsAndCompress(bitmap, MipCount, Format);
}
public override byte[] GetImageData(int ArrayLevel = 0, int MipLevel = 0)
{
if (PlatformSwizzle == PlatformSwizzle.Platform_Switch)
return TegraX1Swizzle.GetImageData(this, IGZStructure.TextureInfo.ImageData, ArrayLevel, MipLevel, 1);
else
return IGZStructure.TextureInfo.ImageData;
}
public override void OnClick(TreeView treeView)
{
ImageEditorBase editor = (ImageEditorBase)LibraryGUI.GetActiveContent(typeof(ImageEditorBase));
if (editor == null)
{
editor = new ImageEditorBase();
editor.Dock = DockStyle.Fill;
LibraryGUI.LoadEditor(editor);
}
editor.LoadProperties(GenericProperties);
editor.LoadImage(this);
}
public void Unload()
{
}
public byte[] Save()
{
//Apply the image info block from this image
IGZStructure.TextureInfo.Width = (ushort)this.Width;
IGZStructure.TextureInfo.Height = (ushort)this.Height;
IGZStructure.TextureInfo.MipCount = (ushort)this.MipCount;
IGZStructure.TextureInfo.Depth = (ushort)this.Depth;
IGZStructure.TextureInfo.ArrayCount = (ushort)this.ArrayCount;
IGZStructure.TextureInfo.FormatInfo.Format = this.Format;
IGZStructure.TextureInfo.FormatInfo.Platform = this.PlatformFormat;
IGZStructure.StringTable[0] = this.Text;
var mem = new System.IO.MemoryStream();
IGZStructure.Write(new FileWriter(mem));
return mem.ToArray();
}
}
}

View file

@ -361,7 +361,7 @@ namespace FirstPlugin
Formats.Add(typeof(G1T)); Formats.Add(typeof(G1T));
Formats.Add(typeof(BFLYT)); Formats.Add(typeof(BFLYT));
Formats.Add(typeof(ZSI)); Formats.Add(typeof(ZSI));
Formats.Add(typeof(IGZ)); Formats.Add(typeof(IGZ_TEX));
//Unfinished wip formats not ready for use //Unfinished wip formats not ready for use
if (Runtime.DEVELOPER_DEBUG_MODE) if (Runtime.DEVELOPER_DEBUG_MODE)

View file

@ -229,6 +229,7 @@ namespace Toolbox.Library
{ TEX_FORMAT.R32G32B32A32_FLOAT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) }, { TEX_FORMAT.R32G32B32A32_FLOAT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R32G32B32A32_SINT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) }, { TEX_FORMAT.R32G32B32A32_SINT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R32G32B32A32_UINT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) }, { TEX_FORMAT.R32G32B32A32_UINT, new FormatInfo(16, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R32G32B32_FLOAT, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R16G16B16A16_FLOAT, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) }, { TEX_FORMAT.R16G16B16A16_FLOAT, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R16G16B16A16_SINT, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) }, { TEX_FORMAT.R16G16B16A16_SINT, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) },
{ TEX_FORMAT.R16G16B16A16_SNORM, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) }, { TEX_FORMAT.R16G16B16A16_SNORM, new FormatInfo(8, 1, 1, 1, TargetBuffer.Color) },

View file

@ -26,7 +26,7 @@ namespace Toolbox.Library.Rendering
} }
public class Vertex public class Vertex
{ {
public Vector3 pos = new Vector3(0); public Vector3 pos = new Vector3(0);
public Vector3 nrm = new Vector3(0); public Vector3 nrm = new Vector3(0);
public Vector4 col = new Vector4(1); public Vector4 col = new Vector4(1);