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); }
public override void Load(ExtendedBinaryReader reader, bool keepOpen = false) { // Check if file has a signature string sig = reader.ReadSignature(); if (sig == "STSC") { // Newer script format uint headerSize = reader.ReadUInt32(); Version = reader.ReadUInt32(); switch (Version) { case 4: // Date A Live: Twin Edition Rio Reincarnation (PSV) ScriptID = reader.ReadUInt16(); break; case 7: // Date A Live: Rio Reincarnation (PC) ScriptName = reader.ReadNullTerminatedString(); reader.JumpAhead((uint)(0x20 - (ScriptName.Length + 1))); reader.JumpAhead(12); ScriptID = reader.ReadUInt32(); break; } } else { // Older script format // Jump back as older scripts have much smaller headers reader.JumpBehind(4); ScriptID = reader.ReadUInt16(); } // Stupid workaround to find the end of the code segment reader.Offset = (uint)reader.BaseStream.Length; while (true) { byte opcode = reader.ReadByte(); if (opcode >= 0x94) { throw new STSCDisassembleException(this, $"Got opcode 0x{opcode:X2} at 0x{reader.BaseStream.Position - 1:X8} in \"{ScriptName}\"" + " There is no opcodes larger than 0x93!"); } // Check if its a known instruction if (STSCInstructions.DALRRInstructions[opcode] == null) { throw new STSCDisassembleException(this, $"Got opcode 0x{opcode:X2} at 0x{reader.BaseStream.Position - 1:X8} in \"{ScriptName}\"" + " This opcode is unknown!"); } var instruction = STSCInstructions.DALRRInstructions[opcode].Read(reader); Instructions.Add(instruction); if (reader.BaseStream.Position >= reader.Offset) { break; } } }
// 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; } } }
public override void Load(Stream fileStream) { ExtendedBinaryReader reader = new ExtendedBinaryReader(fileStream) { Offset = 0x20 }; long pos = 0; NinjaInfo = new NinjaInfo() { NodeName = new string(reader.ReadChars(4)) }; uint NodeLength = reader.ReadUInt32(); uint NodeCount = reader.ReadUInt32(); uint Unknown1 = reader.ReadUInt32(); //Seems to always be 0x20 (at least in XN*s)? uint Unknown2 = reader.ReadUInt32(); //Footer Offset Table Start? uint Unknown3 = reader.ReadUInt32(); //Footer Offset Table Data Start? uint Unknown4 = reader.ReadUInt32(); //Footer Offset Table Length? uint Unknown5 = reader.ReadUInt32(); //Seems to always be 1 (at least in XN*s)? for (int i = 0; i < NodeCount; i++) { //Determine type of node to read string NextNodeName = new string(reader.ReadChars(4)); uint NextNodeLength = reader.ReadUInt32(); reader.JumpBehind(8); switch (NextNodeName) { case "NXTL": case "NZTL": NinjaTextureList = ReadNinjaTextureList(reader, pos); break; case "NXEF": NinjaEffectList = ReadNinjaEffectList(reader, pos); break; case "NXNN": NinjaNodeNameList = ReadNinjaNodeNameList(reader, pos); break; case "NXOB": case "NZOB": NinjaObject = ReadNinjaObject(reader, pos); break; default: reader.JumpAhead(8); reader.JumpAhead(NextNodeLength); //Console.WriteLine($"Block {NextNodeName} Not Implemented!"); break; } } }
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 override void Load(Stream fileStream) { // Header var reader = new ExtendedBinaryReader(fileStream); // Apparently SEGA doesn't even do signature checking (try loading an AR in-game // with the first 0xC bytes set to 0, it works just fine), so why should we? reader.JumpAhead(0xC); Padding = reader.ReadUInt32(); // Data while (fileStream.Position < fileStream.Length) { reader.Offset = (uint)fileStream.Position; uint dataEndOffset = reader.ReadUInt32(); uint dataLength = reader.ReadUInt32(); uint dataStartOffset = reader.ReadUInt32(); uint unknown1 = reader.ReadUInt32(); uint unknown2 = reader.ReadUInt32(); string name = reader.ReadNullTerminatedString(); reader.JumpTo(dataStartOffset, false); var data = reader.ReadBytes((int)dataLength); reader.JumpTo(dataEndOffset, false); var file = new ArchiveFile() { Name = name, Data = data }; Data.Add(file); } }
/// <summary> /// Load file from Stream /// </summary> /// <param name="stream">The stream to read data from</param> /// <param name="autoDecompress">Automatically check for full file compression</param> /// <param name="keepOpen">Should the stream be kept open?</param> public virtual void Load(Stream stream, bool autoDecompress = true, bool keepOpen = false) { var reader = new ExtendedBinaryReader(stream); if (autoDecompress) { // Decompress Zlib stream if (reader.PeekSignature() == "ZLIB") { // Skip ZLIB Header reader.JumpAhead(14); // Decompress stream using (var deflate = new DeflateStream(reader.BaseStream, CompressionMode.Decompress, false)) reader.SetStream(deflate.CacheStream()); // Set Endianness of the reader reader.SetEndian(UseBigEndian); // Parse file Load(reader); return; } } // Set Endianness of the reader reader.SetEndian(UseBigEndian); // Parse File Load(reader, keepOpen); }
// 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 void Load(ExtendedBinaryReader reader) { SourceX = reader.ReadSingle(); SourceY = reader.ReadSingle(); DestinX = reader.ReadSingle(); DestinY = reader.ReadSingle(); reader.JumpAhead(0x30); // Unknown }
public void Load(ExtendedBinaryReader reader) { TextureFullPath = reader.ReadSignature(0x200).Trim('\0'); TextureFileName = reader.ReadSignature(0x080).Trim('\0'); TextureWidth = reader.ReadInt32(); TextureHeight = reader.ReadInt32(); reader.JumpAhead(0x84); // Unknown }
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 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 }); } }
// Methods public override void Read(ExtendedBinaryReader reader) { // BINA Header string sig = reader.ReadSignature(4); if (sig != Signature) { throw new InvalidSignatureException(Signature, sig); } // Version String string verString = reader.ReadSignature(3); if (!ushort.TryParse(verString, out Version)) { Console.WriteLine( "WARNING: BINA header version was invalid! ({0})", verString); } reader.IsBigEndian = IsBigEndian = (reader.ReadChar() == BigEndianFlag); FileSize = reader.ReadUInt32(); ushort nodeCount = reader.ReadUInt16(); ushort unknown1 = reader.ReadUInt16(); // Always 0? Padding?? // TODO: Read Nodes Properly if (nodeCount < 1) { return; } // DATA Header string dataSig = reader.ReadSignature(); if (dataSig != DataSignature) { throw new InvalidSignatureException(DataSignature, dataSig); } DataLength = reader.ReadUInt32(); StringTableOffset = reader.ReadUInt32(); StringTableLength = reader.ReadUInt32(); FinalTableLength = reader.ReadUInt32(); // Additional data ushort additionalDataLength = reader.ReadUInt16(); ushort unknown3 = reader.ReadUInt16(); // Padding? reader.JumpAhead(additionalDataLength); reader.Offset = (uint)reader.BaseStream.Position; }
public void Load(ExtendedBinaryReader reader) { LayerName = reader.ReadSignature(0x20); uint unknown20 = reader.ReadUInt32(); TextureID = reader.ReadInt32(); uint Offset = reader.ReadUInt32(); uint unknown2C = reader.ReadUInt32(); // uint oldpos = (uint)reader.GetPosition(); reader.JumpTo(Offset); reader.JumpAhead(0x164); LayerOffX = reader.ReadSingle(); LayerOffY = reader.ReadSingle(); reader.JumpAhead(4); LayerWidth = reader.ReadSingle(); LayerHeight = reader.ReadSingle(); reader.JumpAhead(0x88); // Unknown /* * Top Left * Top Right * Bottom Left * Bottom Right */ for (int i = 0; i < 4; ++i) { Verts.Add(new MAVert(reader)); } reader.JumpTo(oldpos); reader.JumpAhead(0x84); // Unknown }
public static byte[] ReadAndDecompress(ExtendedBinaryReader reader) { var stream = new MemoryStream(); uint decompressedSize = reader.ReadUInt32(); uint compressedSize = reader.ReadUInt32(); byte copyByte = reader.ReadByte(); reader.JumpAhead(3); uint dataStartOffset = (uint)reader.BaseStream.Position; while (stream.Position < decompressedSize) { byte b = reader.ReadByte(); if (b == copyByte) { byte returnByte = reader.ReadByte(); if (returnByte == copyByte) { stream.WriteByte(returnByte); continue; } if (returnByte >= copyByte) { returnByte--; } uint offset = (uint)stream.Position - returnByte; byte length = reader.ReadByte(); uint currentPosition = (uint)stream.Position; stream.Position = offset; byte[] buffer = new byte[length]; stream.Read(buffer, 0, length); stream.Position = currentPosition; stream.Write(buffer, 0, length); } else { stream.WriteByte(b); } } return(stream.ToArray()); }
// Methods public override void Load(Stream fileStream) { var reader = new ExtendedBinaryReader(fileStream, Encoding.ASCII, false); // Checks the Magic reader.JumpAhead(0x8); // Jump to Magic Magic = reader.ReadUInt32(); // Magic reader.JumpBehind(0xC); // Jump back to the start if (Magic == (uint)Magics.Shadow6 || Magic == (uint)Magics.Shadow5) { LoadShadowArchive(reader); // Shadow the Hedgehog Archive } else { LoadHeroesArchive(reader); // Sonic Heroes Archive } }
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); }
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 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 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); }
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 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); }
// Methods public override void Read(ExtendedBinaryReader reader) { // We need to know whether the file is big or little endian first var pos = reader.BaseStream.Position; reader.BaseStream.Position += 0x14; reader.IsBigEndian = false; // Version String/Endian Flag uint binaFlags = reader.ReadUInt32(); string verString = "xyz"; // Just 3 chars that would fail ushort.TryParse unsafe { // Endian Flag reader.IsBigEndian = IsBigEndian = ((char)( (binaFlags & 0xFF000000) >> 24) == BigEndianFlag); // Quick way to grab the last 3 bytes from binaFlags (which // are chars) and stuff them into a string we can then // safely parse into a ushort via ushort.TryParse fixed(char *vp = verString) { *vp = (char)((binaFlags & 0xFF0000) >> 16); vp[1] = (char)((binaFlags & 0xFF00) >> 16); vp[2] = (char)(binaFlags & 0xFF); } } if (!ushort.TryParse(verString, out Version)) { Console.WriteLine( "WARNING: BINA header version was invalid! ({0})", verString); } // Alright, cool, *NOW* we can read the rest of the header reader.BaseStream.Position = pos; // Header FileSize = reader.ReadUInt32(); FinalTableOffset = reader.ReadUInt32(); FinalTableLength = reader.ReadUInt32(); uint unknown1 = reader.ReadUInt32(); if (unknown1 != 0) { Console.WriteLine($"WARNING: Unknown1 is not zero! ({unknown1})"); } ushort unknownFlag1 = reader.ReadUInt16(); if (unknownFlag1 != 0) { Console.WriteLine($"WARNING: UnknownFlag1 is not zero! ({unknownFlag1})"); } IsFooterMagicPresent = (reader.ReadUInt16() == 1); // FooterNodeCount? reader.JumpAhead(4); // BINA Signature string sig = reader.ReadSignature(4); if (sig != Signature) { throw new InvalidSignatureException(Signature, sig); } // TODO: Find out what this is. Maybe additional data length? uint unknown2 = reader.ReadUInt32(); if (unknown2 != 0) { Console.WriteLine($"WARNING: Unknown2 is not zero! ({unknown2})"); } reader.Offset = (uint)reader.BaseStream.Position; }
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); }
// 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; } } }