public NXNN ReadNodeNames(ExtendedBinaryReader reader, long pos) { NodeTree = new NXNN() { TreeNode = new string(reader.ReadChars(4)), NodeLength = reader.ReadUInt32() }; pos = reader.BaseStream.Position; //Save Position reader.JumpTo(reader.ReadUInt32() + 4, false); var nodeCount = reader.ReadUInt32(); reader.JumpTo(reader.ReadUInt32(), false); for (int i = 0; i < nodeCount; i++) { NodeTree node = new NodeTree(); node.NodeIndex = reader.ReadUInt32(); var nameOffset = reader.ReadUInt32(); long nodePos = reader.BaseStream.Position; //Save Position reader.JumpTo(nameOffset, false); node.NodeName = reader.ReadNullTerminatedString(); reader.JumpTo(nodePos); NodeTree.Nodes.Add(node); } reader.JumpTo(pos); reader.JumpAhead(NodeTree.NodeLength); return(NodeTree); }
public NXTL ReadTextureList(ExtendedBinaryReader reader, long pos) { TextureList = new NXTL() { TextureListNode = new string(reader.ReadChars(4)), NodeLength = reader.ReadUInt32() }; pos = reader.BaseStream.Position; //Save Position reader.JumpTo(reader.ReadUInt32(), false); TextureList.TextureCount = reader.ReadUInt32(); uint textureListOffset = reader.ReadUInt32(); reader.JumpTo(textureListOffset, false); for (int i = 0; i < TextureList.TextureCount; i++) { reader.JumpAhead(0x4); uint textureNameOffset = reader.ReadUInt32(); long texturePos = reader.BaseStream.Position; //Save Position reader.JumpTo(textureNameOffset, false); TEXFILE tex = new TEXFILE(); tex.Filename = reader.ReadNullTerminatedString(); reader.JumpTo(texturePos); tex.Filters = reader.ReadUInt32(); reader.JumpAhead(0x8); TextureList.Textures.Add(tex); } reader.JumpTo(pos); reader.JumpAhead(TextureList.NodeLength); return(TextureList); }
// Methods public override void Load(Stream fileStream) { // HEADER var reader = new ExtendedBinaryReader(fileStream, Encoding.ASCII, true); uint fileCount = reader.ReadUInt32(); uint entriesOffset = reader.ReadUInt32(); uint fileDataOffset = reader.ReadUInt32(); // DATA var stringBuffer = new char[stringBufferSize]; var fileEntries = new FileEntry[fileCount]; reader.JumpTo(entriesOffset, true); for (uint i = 0; i < fileCount; ++i) { // Read File Name reader.Read(stringBuffer, 0, stringBufferSize); string fileName = new string(stringBuffer).Replace("\0", string.Empty); // Read File Entry Data uint fileIndex = reader.ReadUInt32(); fileEntries[fileIndex] = new FileEntry() { FileName = fileName, FileIndex = fileIndex, DataOffset = reader.ReadUInt32(), DataLength = reader.ReadUInt32(), UncompressedSize = reader.ReadUInt32() }; } // Read File Data for (uint i = 0; i < fileCount; ++i) { var fileEntry = fileEntries[i]; var data = new byte[fileEntry.DataLength]; int pos = 0; reader.JumpTo(fileEntry.DataOffset, true); while (pos < data.Length) { // TODO: De-compress files. pos += reader.Read(data, pos, data.Length - pos); } // Add File to Files List Data.Add(new ArchiveFile(fileEntry.FileName, data)); } }
/// <summary> /// Gets the StreamBlock from instruction and jumps to it /// </summary> /// <param name="index">Database Param Index</param> /// <param name="reader">The reader used to jump to the block</param> /// <returns>a StreamBlock containing the range of data to access</returns> public StreamBlock GetStreamBlockAndJump(int index, ExtendedBinaryReader reader) { var streamBlock = Instructions[index].GetArgument <StreamBlock>(1); reader.JumpTo(streamBlock); return(streamBlock); }
// TODO protected void LoadShadowArchive(ExtendedBinaryReader reader) { reader.JumpAhead(0x4); // Unknown, Seems to always be 0 uint fileSize = reader.ReadUInt32(); // File Size - 0xC uint magic = reader.ReadUInt32(); // Magic string ONEVersion = reader.ReadNullTerminatedString(); // Gets the version String reader.FixPadding(); // Aligns the reader uint fileCount = reader.ReadUInt32(); // File Count reader.JumpAhead(0x38 * 2 + 0x20); // Jump to the third/first entry bool isVersion6 = ONEVersion == "ONE Ver 0.60"; // Checks if its version is 0.60 int fileNameLength = isVersion6 ? 0x2C : 0x20; // The max file name size // Read File List var files = new FileEntry[FileEntryCount]; for (int i = 0; i < fileCount; i++) { var entry = new FileEntry(); entry.FileName = reader.ReadSignature( fileNameLength).Replace("\0", string.Empty); entry.UncompressedSize = reader.ReadUInt32(); entry.DataOffset = reader.ReadUInt32(); reader.JumpAhead(4); // Unknown, Seems to always be 1 if (!isVersion6) { reader.JumpAhead(0xC); // Unknown, Seems to always be 0 } files[i] = entry; } // Read File Data if (files.Length > 0) { reader.JumpTo(files[0].DataOffset + 0xC); for (int i = 0; i < fileCount; ++i) { // Compute the file's data length files[i].DataLength = ((i == fileCount - 1) ? fileSize + 0xC : files[i + 1].DataOffset) - files[i].DataOffset; var file = new ArchiveFile() { Name = files[i].FileName, Data = reader.ReadBytes( (int)files[i].DataLength) // TODO: Decompress file }; Data.Add(file); } } }
public override void Load(Stream fileStream) { ExtendedBinaryReader reader = new ExtendedBinaryReader(fileStream) { Offset = 0x20 }; long pos = 0; // NINJA INFO [N*IF] InfoList = new NXIF() { HeaderInfoNode = new string(reader.ReadChars(4)), NodeLength = reader.ReadUInt32(), NodeCount = reader.ReadUInt32() }; reader.JumpTo(InfoList.NodeLength + 8); for (int i = 0; i < InfoList.NodeCount; i++) { string nodeName = new string(reader.ReadChars(4)); uint nodeLength = reader.ReadUInt32(); reader.JumpBehind(8); switch (nodeName) { case "NXTL": case "NZTL": // NINJA TEXTURE LIST [N*TL] TextureList = ReadTextureList(reader, pos); break; case "NXEF": // NINJA EFFECTS [N*EF] EffectList = ReadEffectList(reader, pos); break; case "NXNN": // NINJA NODE NAMES [N*NN] NodeTree = ReadNodeNames(reader, pos); break; case "NXOB": case "NZOB": ObjectList = ReadNodes(reader, pos); break; default: reader.JumpAhead(8); reader.JumpAhead(nodeLength); Console.WriteLine($"Block {nodeName} Not Implemented!"); break; } } }
// Methods public override void Read(ExtendedBinaryReader reader) { FileSize = reader.ReadUInt32(); RootNodeType = reader.ReadUInt32(); RootNodeSize = reader.ReadUInt32(); RootNodeOffset = reader.ReadUInt32(); FooterOffset = reader.ReadUInt32(); FileEndOffset = reader.ReadUInt32(); reader.Offset = RootNodeOffset; reader.JumpTo(RootNodeOffset); }
public NinjaTextureList ReadNinjaTextureList(ExtendedBinaryReader reader, long pos) { NinjaTextureList = new NinjaTextureList() { NodeName = new string(reader.ReadChars(4)) }; uint NodeLength = reader.ReadUInt32(); pos = reader.BaseStream.Position; //Save Position uint NodeOffset = reader.ReadUInt32(); reader.JumpTo(NodeOffset, false); uint TextureCount = reader.ReadUInt32(); uint TextureListOffset = reader.ReadUInt32(); reader.JumpTo(TextureListOffset, false); for (int i = 0; i < TextureCount; i++) { uint Unknown1 = reader.ReadUInt32(); //Seems to always be 0 (at least in XN*s)? (Padding?) uint TextureNameOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(TextureNameOffset, false); NinjaTextureFile TextureFile = new NinjaTextureFile() { TextureName = reader.ReadNullTerminatedString() }; reader.JumpTo(currentPos, true); TextureFile.Filters = reader.ReadUInt32(); uint Unknown2 = reader.ReadUInt32(); //Seems to always be 0 (at least in XN*s)? (Padding?) uint Unknown3 = reader.ReadUInt32(); //Seems to always be 0 (at least in XN*s)? (Padding?) NinjaTextureList.TextureFiles.Add(TextureFile); } reader.JumpTo(pos, true); reader.JumpAhead(NodeLength); return(NinjaTextureList); }
public NinjaNodeNameList ReadNinjaNodeNameList(ExtendedBinaryReader reader, long pos) { NinjaNodeNameList = new NinjaNodeNameList() { NodeName = new string(reader.ReadChars(4)) }; uint NodeLength = reader.ReadUInt32(); pos = reader.BaseStream.Position; //Save Position uint NodeOffset = reader.ReadUInt32(); reader.JumpTo(NodeOffset, false); uint Unknown1 = reader.ReadUInt32(); //Padding? uint NodeTableCount = reader.ReadUInt32(); uint NodeTableOffset = reader.ReadUInt32(); reader.JumpTo(NodeTableOffset, false); for (int i = 0; i < NodeTableCount; i++) { NinjaNodeName NodeName = new NinjaNodeName() { ID = reader.ReadUInt32() }; uint NodeNameIndex = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(NodeNameIndex, false); NodeName.Name = reader.ReadNullTerminatedString(); reader.JumpTo(currentPos, true); NinjaNodeNameList.NinjaNodeNames.Add(NodeName); } reader.JumpTo(pos, true); reader.JumpAhead(NodeLength); return(NinjaNodeNameList); }
public NXEF ReadEffectList(ExtendedBinaryReader reader, long pos) { EffectList = new NXEF() { EffectNode = new string(reader.ReadChars(4)), NodeLength = reader.ReadUInt32() }; pos = reader.BaseStream.Position; //Save Position reader.JumpTo(reader.ReadUInt32() + 4, false); var effectTypeCount = reader.ReadUInt32(); var effectTypeOffset = reader.ReadUInt32(); var techiqueCount = reader.ReadUInt32(); var techniqueOffset = reader.ReadUInt32(); reader.JumpTo(effectTypeOffset, false); for (int i = 0; i < effectTypeCount; i++) { EFFFILE effFile = new EFFFILE(); effFile.Type = reader.ReadUInt32(); var jumpPoint = reader.ReadUInt32(); long effectPos = reader.BaseStream.Position; //Save Position reader.JumpTo(jumpPoint, false); effFile.Filename = reader.ReadNullTerminatedString(); reader.JumpTo(effectPos); EffectList.Effects.Add(effFile); } reader.JumpTo(techniqueOffset, false); for (int i = 0; i < techiqueCount; i++) { TECHNAME tech = new TECHNAME(); tech.Type = reader.ReadUInt32(); tech.NodeID = reader.ReadUInt32(); var jumpPoint = reader.ReadUInt32(); long techPos = reader.BaseStream.Position; //Save Position reader.JumpTo(jumpPoint, false); tech.Filename = reader.ReadNullTerminatedString(); reader.JumpTo(techPos); EffectList.Techs.Add(tech); } reader.JumpTo(pos); reader.JumpAhead(EffectList.NodeLength); return(EffectList); }
// Methods public static void Read(HavokFile h, ExtendedBinaryReader reader) { // Header reader.JumpAhead(0x10); // A lot of this was gathered from the Max Havok exporter. byte bytesInPointer = reader.ReadByte(); reader.IsBigEndian = !reader.ReadBoolean(); byte reusePaddingOpt = reader.ReadByte(); byte emptyBaseClassOpt = reader.ReadByte(); // We jump around a lot here, but there's not really a much cleaner way to do it. reader.JumpTo(8, true); h.UserTag = reader.ReadUInt32(); h.ClassVersion = reader.ReadInt32(); reader.JumpAhead(4); uint sectionsCount = reader.ReadUInt32(); uint unknown1 = reader.ReadUInt32(); ulong padding1 = reader.ReadUInt64(); uint unknown2 = reader.ReadUInt32(); h.ContentsVersion = reader.ReadNullTerminatedString(); reader.JumpAhead(9); // Seems to be padding // Sections for (uint i = 0; i < sectionsCount; ++i) { string sectionName = new string(reader.ReadChars(0x10)); sectionName = sectionName.Replace("\0", string.Empty); // TODO reader.JumpAhead(0x20); } // Padding Checks if (padding1 != 0) { Console.WriteLine($"WARNING: Padding1 != 0 ({padding1})"); } // TODO throw new NotImplementedException(); }
public override void Load(Stream fileStream) { ExtendedBinaryReader reader = new ExtendedBinaryReader(fileStream) { Offset = 0x20 }; reader.JumpAhead(16); reader.JumpTo(reader.ReadUInt32(), false); reader.JumpAhead(8); var offsetCount = reader.ReadUInt32(); reader.JumpAhead(4); for (int i = 0; i < offsetCount; i++) { Offsets.Add(reader.ReadUInt32()); Offsets[i] = Offsets[i] + 0x20; } }
public void Read(ExtendedBinaryReader reader, uint textureCount) { // Texture Offsets var textureOffsets = new uint[textureCount]; for (uint i = 0; i < textureCount; ++i) { textureOffsets[i] = reader.ReadUInt32(); } // Textures textures.Clear(); for (uint i = 0; i < textureCount; ++i) { reader.JumpTo(textureOffsets[i], false); textures.Add(new GensTexture( reader.ReadNullTerminatedString())); } }
public override void Load(Stream fileStream) { var reader = new ExtendedBinaryReader(fileStream, false); reader.JumpAhead(4); // CRC32? int fileCount = reader.ReadInt32(); var fileEntries = new List <FileEntry>(); for (int i = 0; i < fileCount; ++i) { var fileEntry = new FileEntry(); fileEntry.FileName = reader.ReadSignature(0x40).Replace("\0", ""); fileEntry.DataUncompressedSize = reader.ReadUInt32(); fileEntry.DataSize = reader.ReadUInt32(); fileEntry.DataOffset = reader.ReadUInt32(); fileEntry.Compressed = reader.ReadByte() == 1; reader.JumpAhead(3); // Other Attributes? fileEntries.Add(fileEntry); } foreach (var fileEntry in fileEntries) { reader.JumpTo(fileEntry.DataOffset); byte[] data = null; if (fileEntry.Compressed) { data = ReadAndDecompress(reader); } else { data = reader.ReadBytes((int)fileEntry.DataUncompressedSize); } // Adds the File Data.Add(new ArchiveFile() { Name = fileEntry.FileName, Data = data }); } }
public NXOB ReadNodes(ExtendedBinaryReader reader, long pos) { /* * Sonic 4 Decompilation Ref * public NNS_NODE( AppMain.NNS_NODE node ) * { * this.fType = node.fType; * this.iMatrix = node.iMatrix; * this.iParent = node.iParent; * this.iChild = node.iChild; * this.iSibling = node.iSibling; * this.Translation.Assign( node.Translation ); * this.Rotation = node.Rotation; * this.Scaling.Assign( node.Scaling ); * this.InvInitMtx.Assign( node.InvInitMtx ); * this.Center.Assign( node.Center ); * this.Radius = node.Radius; * this.User = node.User; * this.SIIKBoneLength = node.SIIKBoneLength; * this.BoundingBoxY = node.BoundingBoxY; * this.BoundingBoxZ = node.BoundingBoxZ; * } */ ObjectList = new NXOB() { ObjectList = new string(reader.ReadChars(4)), NodeLength = reader.ReadUInt32() }; pos = reader.BaseStream.Position; //Save Position reader.JumpTo(reader.ReadUInt32(), false); reader.JumpAhead(0x10); //Variable Names Copy & Pasted from MaxScript var TexElmTotal = reader.ReadUInt32(); var TexElmOffset = reader.ReadUInt32(); var VertGroupTotal = reader.ReadUInt32(); var VertGroupOffset = reader.ReadUInt32(); var PolyElmTotal = reader.ReadUInt32(); var PolyElmOffset = reader.ReadUInt32(); //Nodes var NodeTotal = reader.ReadUInt32(); var UnknownCount1 = reader.ReadUInt32(); //Count of SOMETHING? var NodeOffset = reader.ReadUInt32(); var UnknownCount2 = reader.ReadUInt32(); //MaxScript calls this NodeTotal, but I'm sure what they call BoneTotal is actually NodeTotal? Seems to be a Count of something var LinkTotal = reader.ReadUInt32(); var LinkOffset = reader.ReadUInt32(); var UnknownCount3 = reader.ReadUInt32(); //Count of SOMETHING? //NNS_NODE reader.JumpTo(NodeOffset, false); for (int i = 0; i < NodeTotal; i++) { Node node = new Node(); node.NODE_TYPE = reader.ReadUInt32(); node.NODE_MATRIX = reader.ReadUInt16(); node.NODE_PARENT = reader.ReadUInt16(); node.NODE_CHILD = reader.ReadUInt16(); node.NODE_SIBLING = reader.ReadUInt16(); for (int n = 0; n < 3; n++) { node.NODE_TRN.Add(reader.ReadSingle()); } for (int n = 0; n < 3; n++) { node.NODE_ROT.Add(reader.ReadSingle()); } for (int n = 0; n < 3; n++) { node.NODE_SCL.Add(reader.ReadSingle()); } for (int n = 0; n < 16; n++) { node.NODE_INVINIT_MTX.Add(reader.ReadSingle()); } for (int n = 0; n < 3; n++) { node.NODE_CENTER.Add(reader.ReadSingle()); } node.NODE_RADIUS = reader.ReadSingle(); node.NODE_USER = reader.ReadUInt32(); node.NODE_RSV0 = reader.ReadUInt32(); node.NODE_RSV1 = reader.ReadUInt32(); node.NODE_RSV2 = reader.ReadUInt32(); ObjectList.Nodes.Add(node); } reader.JumpTo(TexElmOffset, false); var Unknown1 = reader.ReadUInt32(); //Assume this is a count??? reader.JumpTo(reader.ReadUInt32(), false); return(ObjectList); }
public override void Load(Stream fileStream) { // Header var reader = new ExtendedBinaryReader(fileStream, true); var entries = new List <FileEntry>(); uint sig = reader.ReadUInt32(); if (sig != Signature) { throw new InvalidSignatureException( Signature.ToString("X"), sig.ToString("X")); } uint fileTableOffset = reader.ReadUInt32(); uint fileTableLength = reader.ReadUInt32(); uint fileDataOffset = reader.ReadUInt32(); uint unknown5 = reader.ReadUInt32(); uint unknown6 = reader.ReadUInt32(); uint unknown7 = reader.ReadUInt32(); uint unknown8 = reader.ReadUInt32(); // File/Directory Entries long fileTableEnd = (fileTableOffset + fileTableLength); reader.JumpTo(fileTableOffset); while (fileStream.Position < fileTableEnd) { bool isDirectory = reader.ReadBoolean(); byte padding1 = reader.ReadByte(); if (padding1 != 0) { fileStream.Position -= 2; // go bacc break; } var fileEntry = new FileEntry() { IsDirectory = isDirectory, FileNameOffset = reader.ReadUInt16(), DataOffset = reader.ReadUInt32(), DataLength = reader.ReadUInt32(), DataUncompressedSize = reader.ReadUInt32() }; entries.Add(fileEntry); } // Entry Names uint fileNamesOffset = (uint)fileStream.Position; foreach (var entry in entries) { reader.JumpTo(fileNamesOffset + entry.FileNameOffset); entry.Name = reader.ReadNullTerminatedString(); } // Entry Data ArchiveDirectory dir = null; for (int i = 0; i < entries.Count; ++i) { var entry = entries[i]; // Directory if (entry.IsDirectory) { // Generate a HedgeLib directory entry if (i == 0) { continue; } if (entry.DataOffset >= i) { throw new Exception("Entry DataOffset is invalid"); } var dirEntry = new ArchiveDirectory(entry.Name); if (entry.DataOffset != 0) { var parentEntry = entries[(int)entry.DataOffset]; dirEntry.Parent = parentEntry.Directory; } if (dirEntry.Parent == null) { Data.Add(dirEntry); } else { dirEntry.Parent.Data.Add(dirEntry); } dir = entry.Directory = dirEntry; } // File else { if (dir == null) { throw new Exception("Tried to read a file not in a directory!"); } var data = new byte[entry.DataUncompressedSize]; int offset = 0, size = (int)entry.DataUncompressedSize; reader.JumpTo(entry.DataOffset + 2); using (var gzipStream = new DeflateStream(fileStream, CompressionMode.Decompress, true)) { while (offset < size) { offset += gzipStream.Read(data, offset, (size - offset)); } } // Generate a HedgeLib file entry dir.Data.Add(new ArchiveFile(entry.Name, data)); } } }
public const uint TAGMagic = 0x30474154; // "TAG0" in little-endian // Methods public static void Read(HavokFile h, ExtendedBinaryReader reader) { var fs = reader.BaseStream; long pos = fs.Position; long endPos = pos; var types = new List <string>(); reader.IsBigEndian = true; while (pos < fs.Length) { uint size = reader.ReadUInt32(); string type = new string(reader.ReadChars(4)); bool isParam = (((size & 0xC0000000) >> 24) == 0x40); // Remove the param marker from the beginning of the size if (isParam) { size &= 0xFFFFFF; } size -= 8; pos = fs.Position; endPos = pos + size; Console.WriteLine("{0}: \"{1}\"", (isParam) ? "Parameter" : "Section", type); // Read based on type switch (type) { // SDK Version case "SDKV": h.ContentsVersion = new string(reader.ReadChars((int)size)); Console.WriteLine($"Contents Version: {h.ContentsVersion}"); break; case "DATA": ReadDATASection(); break; // Type Strings case "TSTR": { Console.WriteLine(); while (fs.Position < endPos) { string t = reader.ReadNullTerminatedString(); if (string.IsNullOrEmpty(t)) { continue; } Console.WriteLine(t); types.Add(t); // TODO } Console.WriteLine(); break; } // Type Names (??) case "TNAM": { uint unknown1 = reader.ReadUInt32(); // TODO break; } // Format Strings case "FSTR": { Console.WriteLine(); while (fs.Position < endPos) { string t = reader.ReadNullTerminatedString(); if (string.IsNullOrEmpty(t)) { continue; } Console.WriteLine(t); // TODO } Console.WriteLine(); // TODO break; } } // TODO // Jump ahead to the next parameter if (isParam) { pos = endPos; if (fs.Position != pos) { reader.JumpTo(pos); } } } // Sub-Methods //HavokSection ReadSection() //{ // var section = new HavokSection(); // // TODO // return section; //} void ReadDATASection() { reader.IsBigEndian = false; // TODO ulong unknown1 = reader.ReadUInt64(); ulong unknown2 = reader.ReadUInt64(); ulong unknown3 = reader.ReadUInt64(); ulong unknown4 = reader.ReadUInt64(); ulong unknown5 = reader.ReadUInt64(); for (uint i = 0; i < unknown1; ++i) { string s = reader.ReadNullTerminatedString(); Console.WriteLine(s); } // TODO // Padding Checks if (unknown2 != 0) { Console.WriteLine($"WARNING: DATA Unknown2 != 0 ({unknown2})"); } reader.IsBigEndian = true; // TODO } }
public static byte[] DecompressLZ77(this byte[] compressed) { byte[] buffer = null; using (var reader = new ExtendedBinaryReader(new MemoryStream(compressed))) { int position = 0; long flagPosition = 0; if (reader.ReadSignature() == "LZ77") { int uncompressedSize = reader.ReadInt32(); int lz77Step = reader.ReadInt32(); int offset = reader.ReadInt32(); flagPosition = reader.GetPosition(); reader.JumpTo(offset); buffer = new byte[uncompressedSize]; } int flagCount = 0; int flag = 0; while (true) { if (flagCount == 0) { if (flagPosition >= compressed.Length) { break; } if (flagPosition == reader.GetPosition()) { reader.JumpAhead(1); } flag = compressed[flagPosition++]; flagCount = 8; } if ((flag & 0x80) != 0) { if (reader.GetPosition() + 2 > compressed.Length) { break; } int backStep = reader.ReadByte(); int amount = reader.ReadByte(); for (amount += 3; (amount--) != 0; position++) { if (position >= buffer.Length) { break; } buffer[position] = buffer[position - backStep]; } } else { if (position >= buffer.Length) { break; } buffer[position++] = reader.ReadByte(); } flag <<= 1; flagCount--; } } return(buffer); }
protected void LoadHeroesArchive(ExtendedBinaryReader reader) { // HEADER uint padding = reader.ReadUInt32(); if (padding != 0) { Console.WriteLine("WARNING: Padding is not 0! ({0})", padding); } uint fileSize = reader.ReadUInt32() + 0xC; if (fileSize != reader.BaseStream.Length) { // Written like this to avoid the + operator and keep the line under 100 chars Console.WriteLine("{0} (Got {1} expected {2})", "WARNING: File-Size in archive appears incorrect!", fileSize, reader.BaseStream.Length); } Magic = reader.ReadUInt32(); uint unknown1 = reader.ReadUInt32(); if (unknown1 != 1) { Console.WriteLine("WARNING: Unknown1 is not 1! ({0})", unknown1); } uint dataOffset = reader.ReadUInt32(); // TODO: Ensure this is correct uint magic2 = reader.ReadUInt32(); // DATA var stringBuffer = new char[StringLength]; var fileNames = new string[FileEntryCount]; // File Names for (uint i = 0; i < FileEntryCount; ++i) { if (reader.BaseStream.Position + StringLength >= fileSize) { break; } reader.Read(stringBuffer, 0, StringLength); fileNames[i] = new string(stringBuffer).Replace("\0", string.Empty); } // File Entries reader.JumpTo(dataOffset, true); while (reader.BaseStream.Position < fileSize) { uint fileNameIndex = reader.ReadUInt32(); uint dataLength = reader.ReadUInt32(); uint magic3 = reader.ReadUInt32(); if (dataLength > 0) { var data = reader.ReadBytes((int)dataLength); Data.Add(new ArchiveFile(fileNames[fileNameIndex], data)); } } }
private static SetObject ReadObject(ExtendedBinaryReader reader, SetObjectType objTemplate, string objType, SOBJType type, bool rawDataMode = false) // true = full, false = only remaining bytes { // For some reason these separate values are saved as one uint rather than two ushorts. // Because of this, the values are in a different order depending on endianness, and // this is the easiest known way to read them. uint unknownValue = reader.ReadUInt32(); ushort unknown1 = (ushort)((unknownValue >> 16) & 0xFFFF); ushort objID = (ushort)(unknownValue & 0xFFFF); var obj = new SetObject() { ObjectType = objType, ObjectID = objID }; uint unknown2 = reader.ReadUInt32(); uint unknown3 = reader.ReadUInt32(); float unknown4 = reader.ReadSingle(); float rangeIn = reader.ReadSingle(); float rangeOut = reader.ReadSingle(); uint parent = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0; uint transformsOffset = reader.ReadUInt32(); uint transformCount = reader.ReadUInt32(); uint unknown5 = reader.ReadUInt32(); uint unknown6 = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0; uint unknown7 = (type == SOBJType.LostWorld) ? reader.ReadUInt32() : 0; // Call me crazy, but I have a weird feeling these values aren't JUST padding if (unknown3 != 0 || unknown5 != 0 || unknown6 != 0 || unknown7 != 0) { Console.WriteLine("WARNING: Not padding?! ({0},{1},{2},{3})", unknown3, unknown5, unknown6, unknown7); } // Add custom data to object obj.CustomData.Add("Unknown1", new SetObjectParam(typeof(ushort), unknown1)); obj.CustomData.Add("Unknown2", new SetObjectParam(typeof(uint), unknown2)); obj.CustomData.Add("Unknown3", new SetObjectParam(typeof(uint), unknown3)); obj.CustomData.Add("Unknown4", new SetObjectParam(typeof(float), unknown4)); obj.CustomData.Add("RangeIn", new SetObjectParam(typeof(float), rangeIn)); obj.CustomData.Add("RangeOut", new SetObjectParam(typeof(float), rangeOut)); if (type == SOBJType.LostWorld) { obj.CustomData.Add("Parent", new SetObjectParam(typeof(uint), parent)); } // Skip loading parameters if template doesn't exist if (objTemplate != null) { // Get Raw Byte Length var rawDataLenExtra = objTemplate.GetExtra("RawByteLength"); long paramBegin = reader.BaseStream.Position; int rawLength = 0; if (rawDataLenExtra != null && !string.IsNullOrEmpty(rawDataLenExtra.Value)) { int.TryParse(rawDataLenExtra.Value, out rawLength); } // Read all the data then return to beginning if (rawDataMode == true && rawLength != 0) { obj.CustomData.Add("RawParamData", new SetObjectParam(typeof(byte[]), reader.ReadBytes(rawLength))); reader.JumpTo(paramBegin); } // Parameters foreach (var param in objTemplate.Parameters) { // For compatibility with SonicGlvl templates. if (param.Name == "Unknown1" || param.Name == "Unknown2" || param.Name == "Unknown3" || param.Name == "RangeIn" || param.Name == "RangeOut" || param.Name == "Parent") { continue; } // Read Special Types/Fix Padding if (param.DataType == typeof(uint[])) { // Data Info reader.FixPadding(4); uint arrOffset = reader.ReadUInt32(); uint arrLength = reader.ReadUInt32(); uint arrUnknown = reader.ReadUInt32(); long curPos = reader.BaseStream.Position; // Data var arr = new uint[arrLength]; reader.JumpTo(arrOffset, false); for (uint i = 0; i < arrLength; ++i) { arr[i] = reader.ReadUInt32(); } obj.Parameters.Add(new SetObjectParam(param.DataType, arr)); reader.BaseStream.Position = curPos; continue; } else if (param.DataType == typeof(string)) { // Data Info uint strOffset = reader.ReadUInt32(); uint strUnknown = reader.ReadUInt32(); string str = null; // Data if (strOffset != 0) { long curPos = reader.BaseStream.Position; reader.JumpTo(strOffset, false); str = reader.ReadNullTerminatedString(); reader.BaseStream.Position = curPos; } obj.Parameters.Add(new SetObjectParam(param.DataType, str)); continue; } else if (param.DataType == typeof(float) || param.DataType == typeof(int) || param.DataType == typeof(uint)) { reader.FixPadding(4); } else if (type == SOBJType.LostWorld && param.DataType == typeof(Vector3)) { reader.FixPadding(16); } // Read Data var objParam = new SetObjectParam(param.DataType, reader.ReadByType(param.DataType)); obj.Parameters.Add(objParam); } if (rawDataMode == false) { long knownParamLength = (reader.BaseStream.Position - paramBegin); long remainingBytes = (rawLength - knownParamLength); obj.CustomData.Add("RawParamData", new SetObjectParam(typeof(byte[]), reader.ReadBytes((int)remainingBytes))); } } // Transforms uint childCount = transformCount - 1; obj.Children = new SetObjectTransform[childCount]; reader.JumpTo(transformsOffset, false); obj.Transform = ReadTransform(reader, type == SOBJType.LostWorld); for (uint i = 0; i < childCount; ++i) { obj.Children[i] = ReadTransform(reader, type == SOBJType.LostWorld); } return(obj); }
// Methods public static List <SetObject> Read(ExtendedBinaryReader reader, Dictionary <string, SetObjectType> objectTemplates, SOBJType type) { var objs = new List <SetObject>(); // SOBJ Header var sig = reader.ReadChars(4); if (!reader.IsBigEndian) { Array.Reverse(sig); } string sigString = new string(sig); if (sigString != Signature) { throw new InvalidSignatureException(Signature, sigString); } uint unknown1 = reader.ReadUInt32(); uint objTypeCount = reader.ReadUInt32(); uint objTypeOffsetsOffset = reader.ReadUInt32(); reader.JumpAhead(4); uint objOffsetsOffset = reader.ReadUInt32(); uint objCount = reader.ReadUInt32(); uint unknown2 = reader.ReadUInt32(); // Probably just padding if (unknown2 != 0) { Console.WriteLine("WARNING: Unknown2 != 0! ({0})", unknown2); } uint transformsCount = reader.ReadUInt32(); // Object Offsets var objOffsets = new uint[objCount]; reader.JumpTo(objOffsetsOffset, false); for (uint i = 0; i < objCount; ++i) { objOffsets[i] = reader.ReadUInt32(); objs.Add(new SetObject()); } // Object Types reader.JumpTo(objTypeOffsetsOffset, false); for (uint i = 0; i < objTypeCount; ++i) { // Object Type string objName = reader.GetString(); uint objOfTypeCount = reader.ReadUInt32(); uint objIndicesOffset = reader.ReadUInt32(); long curTypePos = reader.BaseStream.Position; // Objects reader.JumpTo(objIndicesOffset, false); for (uint i2 = 0; i2 < objOfTypeCount; ++i2) { ushort objIndex = reader.ReadUInt16(); long curPos = reader.BaseStream.Position; var obj = new SetObject(); // We do this check here so we can print an offset that's actually helpful if (!objectTemplates.ContainsKey(objName)) { Console.WriteLine("{0} \"{1}\" (Offset: 0x{2:X})! Skipping this object...", "WARNING: No object template exists for object type", objName, (objOffsets[objIndex] + reader.Offset)); // Object Data without a template reader.JumpTo(objOffsets[objIndex], false); obj = ReadObject(reader, null, objName, type); } else { // Object Data with a template reader.JumpTo(objOffsets[objIndex], false); obj = ReadObject(reader, objectTemplates[objName], objName, type); } objs[objIndex] = obj; reader.BaseStream.Position = curPos; } reader.BaseStream.Position = curTypePos; } return(objs); }
public NinjaObject ReadNinjaObject(ExtendedBinaryReader reader, long pos) { NinjaObject = new NinjaObject() { NodeName = new string(reader.ReadChars(4)) }; uint NodeLength = reader.ReadUInt32(); pos = reader.BaseStream.Position; //Save Position uint NodeOffset = reader.ReadUInt32(); reader.JumpTo(NodeOffset, false); NinjaObject.ObjectCenter = reader.ReadVector3(); NinjaObject.ObjectRadius = reader.ReadSingle(); uint ObjectMaterialCount = reader.ReadUInt32(); uint ObjectMaterialOffset = reader.ReadUInt32(); uint ObjectVTXCount = reader.ReadUInt32(); uint ObjectVTXOffset = reader.ReadUInt32(); uint ObjectPrimitiveCount = reader.ReadUInt32(); uint ObjectPrimitiveOffset = reader.ReadUInt32(); uint ObjectNodeCount = reader.ReadUInt32(); NinjaObject.ObjectMaxNodeDepth = reader.ReadUInt32(); uint ObjectNodeOffset = reader.ReadUInt32(); NinjaObject.ObjectMTXPAL = reader.ReadUInt32(); uint ObjectSubObjectCount = reader.ReadUInt32(); uint ObjectSubObjectOffset = reader.ReadUInt32(); NinjaObject.ObjectTextureCount = reader.ReadUInt32(); //Materials reader.JumpTo(ObjectMaterialOffset, false); for (int i = 0; i < ObjectMaterialCount; i++) { //TO-DO: Figure out how all this fits together NinjaObjectMaterial ObjectMaterial = new NinjaObjectMaterial() { MaterialType = reader.ReadUInt32() }; uint MaterialOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(MaterialOffset, false); ObjectMaterial.MaterialFlags = reader.ReadUInt32(); ObjectMaterial.User = reader.ReadUInt32(); uint MaterialColourOffset = reader.ReadUInt32(); uint MaterialLogicOffset = reader.ReadUInt32(); uint MaterialTexDescOffset = reader.ReadUInt32(); reader.JumpTo(MaterialColourOffset, false); ObjectMaterial.MaterialDiffuse = reader.ReadVector4(); ObjectMaterial.MaterialAmbient = reader.ReadVector4(); ObjectMaterial.MaterialSpecular = reader.ReadVector4(); ObjectMaterial.MaterialEmissive = reader.ReadVector4(); ObjectMaterial.MaterialPower = reader.ReadSingle(); reader.JumpTo(MaterialLogicOffset, false); ObjectMaterial.MaterialBlendenable = reader.ReadUInt32(); ObjectMaterial.MaterialSRCBlend = reader.ReadUInt32(); ObjectMaterial.MaterialDSTBlend = reader.ReadUInt32(); ObjectMaterial.MaterialBlendFactor = reader.ReadUInt32(); ObjectMaterial.MaterialBlendOP = reader.ReadUInt32(); ObjectMaterial.MaterialLogicOP = reader.ReadUInt32(); ObjectMaterial.MaterialAlphaEnable = reader.ReadUInt32(); ObjectMaterial.MaterialAlphaFunction = reader.ReadUInt32(); ObjectMaterial.MaterialAlphaRef = reader.ReadUInt32(); ObjectMaterial.MaterialZCompenable = reader.ReadUInt32(); ObjectMaterial.MaterialZFunction = reader.ReadUInt32(); ObjectMaterial.MaterialZUpdateEnable = reader.ReadUInt32(); reader.JumpTo(MaterialTexDescOffset, false); ObjectMaterial.TextureTexMapType = reader.ReadUInt32(); ObjectMaterial.TextureID = reader.ReadUInt32(); ObjectMaterial.TextureOffset = reader.ReadVector2(); ObjectMaterial.TextureBlend = reader.ReadSingle(); ObjectMaterial.TextureInfoPTR = reader.ReadUInt32(); ObjectMaterial.TextureMinFilter = reader.ReadUInt32(); ObjectMaterial.TextureMagFilter = reader.ReadUInt32(); ObjectMaterial.TextureMipMapBias = reader.ReadSingle(); ObjectMaterial.TextureMaxMipLevel = reader.ReadUInt32(); reader.JumpTo(currentPos, true); NinjaObject.ObjectMaterialList.Add(ObjectMaterial); } //Vertexes reader.JumpTo(ObjectVTXOffset, false); for (int i = 0; i < ObjectVTXCount; i++) { NinjaObjectVertex ObjectVertex = new NinjaObjectVertex() { Type = reader.ReadUInt32() }; uint VTXOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(VTXOffset, false); ObjectVertex.VTXFormat = reader.ReadUInt32(); ObjectVertex.VTXFVF = reader.ReadUInt32(); ObjectVertex.VTXSize = reader.ReadUInt32(); uint VTXNumber = reader.ReadUInt32(); uint VTXListOffset = reader.ReadUInt32(); ObjectVertex.VTXBlendNum = reader.ReadUInt32(); uint VTXMTXOffset = reader.ReadUInt32(); ObjectVertex.VTXHDRCommon = reader.ReadUInt32(); ObjectVertex.VTXHDRData = reader.ReadUInt32(); ObjectVertex.VTXHDRLock = reader.ReadUInt32(); reader.JumpTo(VTXListOffset, false); for (int v = 0; v < VTXNumber; v++) { NinjaObjectVertexList Vertex = new NinjaObjectVertexList(); switch (ObjectVertex.VTXSize) { //Any ones other than 52 & 76 are probably wrong here, as they're not in the XTO and are instead based on the MaxScript //This is such a mess case 20: Vertex.Position = reader.ReadVector3(); Vertex.ST0 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 24: Vertex.Position = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); Vertex.ST0 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 28: Vertex.Position = reader.ReadVector3(); Vertex.Normals = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); ObjectVertex.Vertexes.Add(Vertex); break; case 32: Vertex.Position = reader.ReadVector3(); Vertex.Normals = reader.ReadVector3(); Vertex.ST0 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 36: Vertex.Position = reader.ReadVector3(); Vertex.Normals = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); Vertex.ST0 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 44: Vertex.Position = reader.ReadVector3(); Vertex.Normals = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); Vertex.ST0 = reader.ReadVector2(); Vertex.UnknownV2 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 48: Vertex.Position = reader.ReadVector3(); Vertex.Weight3 = reader.ReadVector3(); Vertex.Normals = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); Vertex.ST0 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 52: Vertex.Position = reader.ReadVector3(); Vertex.Weight3 = reader.ReadVector3(); Vertex.MTXIDX = reader.ReadBytes(4); Vertex.Normals = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); Vertex.ST0 = reader.ReadVector2(); ObjectVertex.Vertexes.Add(Vertex); break; case 60: Vertex.Position = reader.ReadVector3(); Vertex.Weight3 = reader.ReadVector3(); Vertex.Normals = reader.ReadVector3(); Vertex.Tan = reader.ReadVector3(); Vertex.BNormal = reader.ReadVector3(); ObjectVertex.Vertexes.Add(Vertex); break; case 72: Vertex.Position = reader.ReadVector3(); Vertex.Weight3 = reader.ReadVector3(); Vertex.MTXIDX = reader.ReadBytes(4); Vertex.Normals = reader.ReadVector3(); Vertex.ST0 = reader.ReadVector2(); Vertex.Tan = reader.ReadVector3(); Vertex.BNormal = reader.ReadVector3(); ObjectVertex.Vertexes.Add(Vertex); break; case 76: Vertex.Position = reader.ReadVector3(); Vertex.Weight3 = reader.ReadVector3(); Vertex.MTXIDX = reader.ReadBytes(4); Vertex.Normals = reader.ReadVector3(); Vertex.RGBA8888 = reader.ReadBytes(4); Vertex.ST0 = reader.ReadVector2(); Vertex.Tan = reader.ReadVector3(); Vertex.BNormal = reader.ReadVector3(); ObjectVertex.Vertexes.Add(Vertex); break; default: Console.WriteLine($"Vertex Size of {ObjectVertex.VTXSize} not handled!"); continue; } } if (VTXMTXOffset != 0) { reader.JumpTo(VTXMTXOffset, false); ObjectVertex.VTXMTX = reader.ReadInt32(); } reader.JumpTo(currentPos, true); NinjaObject.ObjectVertexList.Add(ObjectVertex); } reader.JumpTo(ObjectPrimitiveOffset, false); for (int i = 0; i < ObjectPrimitiveCount; i++) { NinjaObjectPrimitive ObjectPrimitive = new NinjaObjectPrimitive() { Type = reader.ReadUInt32() }; uint PrimitiveListOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(PrimitiveListOffset, false); ObjectPrimitive.Format = reader.ReadUInt32(); ObjectPrimitive.Index = reader.ReadUInt32(); ObjectPrimitive.Strip = reader.ReadUInt32(); uint LengthOffset = reader.ReadUInt32(); uint IndexOffset = reader.ReadUInt32(); ObjectPrimitive.IndexBuf = reader.ReadUInt32(); reader.JumpTo(LengthOffset, false); ObjectPrimitive.IndexLength = reader.ReadUInt16(); //May be the same as Index all the time??? reader.JumpTo(IndexOffset, false); for (int v = 0; v < ObjectPrimitive.Index; v++) { ObjectPrimitive.VertexIndexList.Add(reader.ReadUInt16()); } reader.JumpTo(currentPos, true); NinjaObject.ObjectPrimitiveList.Add(ObjectPrimitive); } reader.JumpTo(ObjectNodeOffset, false); for (int i = 0; i < ObjectNodeCount; i++) { NinjaObjectNodeList Node = new NinjaObjectNodeList() { Type = reader.ReadUInt32(), Matrix = reader.ReadUInt16(), Parent = reader.ReadUInt16(), Child = reader.ReadUInt16(), Sibling = reader.ReadUInt16(), Transform = reader.ReadVector3(), Rotation = reader.ReadVector3(), Scale = reader.ReadVector3() }; for (int v = 0; v < 16; v++) { Node.Invinit.Add(reader.ReadSingle()); } Node.Center = reader.ReadVector3(); Node.User = reader.ReadUInt32(); Node.RSV0 = reader.ReadUInt32(); Node.RSV1 = reader.ReadUInt32(); Node.RSV2 = reader.ReadUInt32(); reader.JumpAhead(0x4); NinjaObject.ObjectNodeList.Add(Node); } reader.JumpTo(ObjectSubObjectOffset, false); for (int i = 0; i < ObjectSubObjectCount; i++) { uint Type = reader.ReadUInt32(); uint NMSST = reader.ReadUInt32(); uint MSSTOffset = reader.ReadUInt32(); uint Textures = reader.ReadUInt32(); uint TexturesOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(MSSTOffset, false); for (int v = 0; v < NMSST; v++) { NinjaObjectSubObject SubObject = new NinjaObjectSubObject() { Center = reader.ReadVector3(), Radius = reader.ReadSingle(), Node = reader.ReadUInt32(), Matrix = reader.ReadUInt32(), Material = reader.ReadUInt32(), VertexList = reader.ReadUInt32(), PrimList = reader.ReadUInt32(), ShaderList = reader.ReadUInt32() }; NinjaObject.ObjectSubObjectList.Add(SubObject); } reader.JumpTo(currentPos, true); } reader.JumpTo(pos, true); reader.JumpAhead(NodeLength); return(NinjaObject); }
// Methods public override void Load(Stream fileStream) { // Signature var reader = new ExtendedBinaryReader( fileStream, Encoding.ASCII, false); string sig = reader.ReadSignature(4); if (sig != Signature) { throw new InvalidSignatureException(Signature, sig); } // Header Header = new DDSHeader() { Size = reader.ReadUInt32(), Flags = reader.ReadUInt32() }; if (!Header.HasFlag(DDSHeader.FLAGS.CAPS) || !Header.HasFlag(DDSHeader.FLAGS.WIDTH) || !Header.HasFlag(DDSHeader.FLAGS.HEIGHT) || !Header.HasFlag(DDSHeader.FLAGS.PIXEL_FORMAT)) { throw new Exception( "Could not load DDS file. Required header flags are missing!"); } Height = reader.ReadUInt32(); Width = reader.ReadUInt32(); Header.PitchOrLinearSize = reader.ReadUInt32(); Header.Depth = reader.ReadUInt32(); Header.MipmapCount = reader.ReadUInt32(); reader.JumpAhead(44); // Skip past padding Header.PixelFormat = new DDSPixelFormat(reader); Header.Caps = reader.ReadUInt32(); Header.Caps2 = reader.ReadUInt32(); Header.Caps3 = reader.ReadUInt32(); Header.Caps4 = reader.ReadUInt32(); reader.JumpTo(Header.Size + 4, true); // Depth uint depth = 1; if (Header.HasFlag(DDSHeader.FLAGS.DEPTH) && Header.HasFlag(DDSHeader.CAPS2.VOLUME)) { depth = Header.Depth; // TODO throw new NotImplementedException( "Reading 3D textures from DDS files is not yet supported."); } else if (Header.HasFlag(DDSHeader.CAPS2.CUBEMAP)) { depth = 6; // TODO throw new NotImplementedException( "Reading DDS cubemaps is not yet supported."); } // MipMaps uint mipmapCount = 1; if (Header.HasFlag(DDSHeader.FLAGS.MIPMAP_COUNT) && Header.HasFlag(DDSHeader.CAPS.MIPMAP)) { mipmapCount = Header.MipmapCount; } MipmapCount = mipmapCount; // Caps if (!Header.HasFlag(DDSHeader.CAPS.TEXTURE)) { throw new Exception( "Could not load DDS file. Required CAPS flag is missing!"); } // TODO // Caps2 // TODO // DX10 Header/Pixel Format uint pixelsPerBlock = 16; byte blockSize; if (Header.PixelFormat.HasFlag(DDSPixelFormat.FLAGS.FOURCC)) { switch ((DDSPixelFormat.FOURCCS)Header.PixelFormat.FourCC) { // DX10 Header case DDSPixelFormat.FOURCCS.DX10: { var dx10Header = new DX10Header(reader); depth = dx10Header.ArraySize; switch ((DX10Header.DXGI_FORMATS)dx10Header.DXGIFormat) { // BC1 case DX10Header.DXGI_FORMATS.BC1_TYPELESS: case DX10Header.DXGI_FORMATS.BC1_UNORM: CompressionFormat = CompressionFormats.RGB_S3TC_DXT1_EXT; blockSize = 8; break; // BC3 case DX10Header.DXGI_FORMATS.BC3_TYPELESS: case DX10Header.DXGI_FORMATS.BC3_UNORM: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT3_EXT; blockSize = 16; break; // BC5 case DX10Header.DXGI_FORMATS.BC5_TYPELESS: case DX10Header.DXGI_FORMATS.BC5_SNORM: case DX10Header.DXGI_FORMATS.BC5_UNORM: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT5_EXT; blockSize = 16; break; // BC7 case DX10Header.DXGI_FORMATS.BC7_TYPELESS: case DX10Header.DXGI_FORMATS.BC7_UNORM: CompressionFormat = CompressionFormats.RGBA_BPTC_UNORM_EXT; blockSize = 16; break; case DX10Header.DXGI_FORMATS.BC7_UNORM_SRGB: CompressionFormat = CompressionFormats.SRGB_ALPHA_BPTC_UNORM_EXT; blockSize = 16; break; // TODO: Add support for BC1 SRGB, BC2, BC3 SRGB, BC4, and BC6 default: throw new NotImplementedException(string.Format( "Reading DX10 DXGI type \"{0}\" is not yet supported.", dx10Header.DXGIFormat)); } break; } // DXT1 case DDSPixelFormat.FOURCCS.DXT1: CompressionFormat = CompressionFormats.RGB_S3TC_DXT1_EXT; blockSize = 8; break; // DXT3 case DDSPixelFormat.FOURCCS.DXT3: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT3_EXT; blockSize = 16; break; // DXT5 case DDSPixelFormat.FOURCCS.DXT5: case DDSPixelFormat.FOURCCS.ATI2: case DDSPixelFormat.FOURCCS.BC5S: CompressionFormat = CompressionFormats.RGBA_S3TC_DXT5_EXT; blockSize = 16; break; // TODO: Add support for DXT2 and DXT4 default: throw new NotImplementedException(string.Format("{0} \"{1}\" {2}", "Reading DDS files with FOURCC", Header.PixelFormat.FourCC, "is not yet supported.")); } } else { if (!Header.PixelFormat.HasFlag(DDSPixelFormat.FLAGS.RGB)) { throw new NotImplementedException( "Reading DDS files without RGB data is not yet supported."); } if (Header.PixelFormat.RGBBitCount % 8 != 0) { throw new InvalidDataException( "RGBBitCount must be divisible by 8."); } if (Header.PixelFormat.RGBBitCount > 32) { throw new InvalidDataException( "RGBBitCount must be less than or equal to 32."); } if (Header.PixelFormat.RGBBitCount != 32) { throw new NotImplementedException( "Reading DDS files with non 32-bit data is not yet supported."); } pixelsPerBlock = 1; CompressionFormat = CompressionFormats.None; blockSize = (byte)(Header.PixelFormat.RGBBitCount / 8); PixelFormat = PixelFormats.RGBA; } // Whether or not uncompressed pixels need to be re-arranged to RGBA bool isARGB = (CompressionFormat == CompressionFormats.None && Header.PixelFormat.RGBBitCount == 32 && Header.PixelFormat.ABitMask == 0xFF000000 && Header.PixelFormat.RBitMask == 0xFF0000 && Header.PixelFormat.GBitMask == 0xFF00 && Header.PixelFormat.BBitMask == 0xFF); // Data uint width = Width, height = Height; ColorData = new byte[mipmapCount * depth][]; for (uint slice = 0; slice < depth; ++slice) { for (uint level = 0; level < mipmapCount; ++level) { // Pad out width/height to 4x4 blocks if (CompressionFormat != CompressionFormats.None) { if (width % 4 != 0) { width = ((width / 4) + 1) * 4; } if (height % 4 != 0) { height = ((height / 4) + 1) * 4; } } // Compute size of this block uint size = ((width * height) / pixelsPerBlock) * blockSize; // Re-arrange uncompressed pixels to RGBA8 format if necessary if (isARGB) { uint p; ColorData[level] = new byte[size]; for (uint i = 0; i < size; i += 4) { // Convert from ARGB8 to RGBA8 p = reader.ReadUInt32(); ColorData[level][i] = (byte)((p & Header.PixelFormat.RBitMask) >> 16); ColorData[level][i + 1] = (byte)((p & Header.PixelFormat.GBitMask) >> 8); ColorData[level][i + 2] = (byte)(p & Header.PixelFormat.BBitMask); ColorData[level][i + 3] = (byte)((p & Header.PixelFormat.ABitMask) >> 24); } } // Otherwise, simply read the block else { ColorData[level] = reader.ReadBytes((int)size); } // Divide width/height by 2 for the next mipmap width /= 2; height /= 2; } } }
public NinjaEffectList ReadNinjaEffectList(ExtendedBinaryReader reader, long pos) { NinjaEffectList = new NinjaEffectList() { NodeName = new string(reader.ReadChars(4)) }; uint NodeLength = reader.ReadUInt32(); pos = reader.BaseStream.Position; //Save Position uint NodeOffset = reader.ReadUInt32(); reader.JumpTo(NodeOffset, false); uint Unknown1 = reader.ReadUInt32(); //Seems to always be 0 (at least in XN*s)? (Padding?) uint EffectTypeCount = reader.ReadUInt32(); uint EffectTypeOffset = reader.ReadUInt32(); uint TechniqueCount = reader.ReadUInt32(); uint TechniqueOffset = reader.ReadUInt32(); uint TechniqueIDXCount = reader.ReadUInt32(); uint TechniqueIDXOffset = reader.ReadUInt32(); //Effect Files reader.JumpTo(EffectTypeOffset, false); for (int i = 0; i < EffectTypeCount; i++) { NinjaEffectFile EffectFile = new NinjaEffectFile() { Type = reader.ReadUInt32() }; uint EffectFilenameOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(EffectFilenameOffset, false); EffectFile.Filename = reader.ReadNullTerminatedString(); reader.JumpTo(currentPos, true); NinjaEffectList.EffectFiles.Add(EffectFile); } //Effect List reader.JumpTo(TechniqueOffset, false); for (int i = 0; i < TechniqueCount; i++) { NinjaEffectTechnique Technique = new NinjaEffectTechnique() { Type = reader.ReadUInt32(), ID = reader.ReadUInt32() }; uint TechniqueNameOffset = reader.ReadUInt32(); long currentPos = reader.BaseStream.Position; //Save Position reader.JumpTo(TechniqueNameOffset, false); Technique.TechniqueName = reader.ReadNullTerminatedString(); reader.JumpTo(currentPos, true); NinjaEffectList.Techniques.Add(Technique); } //Technique IDX (not sure what this is for) reader.JumpTo(TechniqueIDXOffset, false); for (int i = 0; i < TechniqueIDXCount; i++) { NinjaEffectList.TechniqueIDX.Add(reader.ReadUInt16()); } reader.JumpTo(pos, true); reader.JumpAhead(NodeLength); return(NinjaEffectList); }