public SDATInfo(NitroFile sdat, uint offset) { m_Offset = offset; m_Type = sdat.ReadString(m_Offset + 0x00, 4).ToCharArray(); m_Size = sdat.Read32(m_Offset + 0x04); m_RecordOffset = new uint[8]; for (int i = 0; i < 8; i++) { m_RecordOffset[i] = sdat.Read32(m_Offset + 0x08 + (uint)(i * 4)); } m_Reserved = sdat.ReadBlock(m_Offset + 0x28, 24); m_Records = new SDATInfoRecord[8]; for (int i = 0; i < 8; i++) { m_Records[i] = new SDATInfoRecord(sdat, m_Offset + m_RecordOffset[i]); } m_Records0SEQ = new SDATInfoSEQ[m_Records[0].m_Count]; for (int i = 0; i < m_Records[0].m_Count; i++) { m_Records0SEQ[i] = new SDATInfoSEQ(sdat, m_Offset + m_Records[0].m_EntryOffset[i]); } m_Records1SEQARC = new SDATInfoSEQARC[m_Records[1].m_Count]; for (int i = 0; i < m_Records[1].m_Count; i++) { m_Records1SEQARC[i] = new SDATInfoSEQARC(sdat, m_Offset + m_Records[1].m_EntryOffset[i]); } m_Records2BANK = new SDATInfoBANK[m_Records[2].m_Count]; for (int i = 0; i < m_Records[2].m_Count; i++) { m_Records2BANK[i] = new SDATInfoBANK(sdat, m_Offset + m_Records[2].m_EntryOffset[i]); } m_Records3WAVEARC = new SDATInfoWAVEARC[m_Records[3].m_Count]; for (int i = 0; i < m_Records[3].m_Count; i++) { m_Records3WAVEARC[i] = new SDATInfoWAVEARC(sdat, m_Offset + m_Records[3].m_EntryOffset[i]); } m_Records4PLAYER = new SDATInfoPLAYER[m_Records[4].m_Count]; for (int i = 0; i < m_Records[4].m_Count; i++) { m_Records4PLAYER[i] = new SDATInfoPLAYER(sdat, m_Offset + m_Records[4].m_EntryOffset[i]); } m_Records5GROUP = new SDATInfoGROUP[m_Records[5].m_Count]; for (int i = 0; i < m_Records[5].m_Count; i++) { m_Records5GROUP[i] = new SDATInfoGROUP(sdat, m_Offset + m_Records[5].m_EntryOffset[i]); } m_Records6PLAYER2 = new SDATInfoPLAYER2[m_Records[6].m_Count]; for (int i = 0; i < m_Records[6].m_Count; i++) { m_Records6PLAYER2[i] = new SDATInfoPLAYER2(sdat, m_Offset + m_Records[6].m_EntryOffset[i]); } m_Records7STREAM = new SDATInfoSTREAM[m_Records[7].m_Count]; for (int i = 0; i < m_Records[7].m_Count; i++) { m_Records7STREAM[i] = new SDATInfoSTREAM(sdat, m_Offset + m_Records[7].m_EntryOffset[i]); } }
public SDATInfoRecord(NitroFile sdat, uint offset) { m_Offset = offset; m_Count = sdat.Read32(m_Offset); m_EntryOffset = new uint[m_Count]; for (int i = 0; i < m_Count; i++) { m_EntryOffset[i] = sdat.Read32(m_Offset + 0x04 + (uint)(i * 4)); } }
private void UpdateEntries(String msg, int index) { m_MsgData[index] = msg; m_ShortVersions[index] = ShortVersion(msg, index); int lengthDif = EncodeString(msg).Count - m_StringLengths[index]; m_StringLengths[index] += lengthDif; //Make or remove room for the new string if needed (don't need to for last entry) if (lengthDif > 0 && index != m_MsgData.Length - 1) { uint curStringStart = m_StringHeaderData[index] + m_DAT1Start; uint nextStringStart = m_StringHeaderData[index + 1] + m_DAT1Start; byte[] followingData = file.ReadBlock(nextStringStart, (uint)(file.m_Data.Length - nextStringStart)); for (int i = (int)curStringStart; i < (int)nextStringStart + lengthDif; i++) { file.Write8((uint)i, 0);// Fill the gap with zeroes } file.WriteBlock((uint)(nextStringStart + lengthDif), followingData); } else if (lengthDif < 0 && index != m_MsgData.Length - 1) { // lengthDif is negative, -- + uint nextStringStart = m_StringHeaderData[index + 1] + m_DAT1Start; byte[] followingData = file.ReadBlock(nextStringStart, (uint)(file.m_Data.Length - nextStringStart)); file.WriteBlock((uint)(nextStringStart + lengthDif), followingData); int oldSize = file.m_Data.Length; Array.Resize(ref file.m_Data, oldSize + lengthDif);// Remove duplicate data at end of file } // Update pointers to string entry data if (lengthDif != 0) { for (int i = index + 1; i < m_MsgData.Length; i++) { if (lengthDif > 0) { m_StringHeaderData[i] += (uint)lengthDif; } else if (lengthDif < 0) { m_StringHeaderData[i] = (uint)(m_StringHeaderData[i] + lengthDif); } file.Write32(m_StringHeaderAddr[i], m_StringHeaderData[i]); file.Write16(m_StringWidthAddr[i], m_StringWidth[i]); file.Write16(m_StringHeightAddr[i], m_StringHeight[i]); } } // Update total file size file.Write32(0x08, (uint)(int)(file.Read32(0x08) + lengthDif)); // Update DAT1 size file.Write32(m_DAT1Start - 0x04, (uint)(int)(file.Read32(m_DAT1Start - 0x04) + lengthDif)); }
public OctreeNode(NitroFile file, uint baseoffset, uint offset, Vector3 pos, Vector3 size) { m_Pos = pos; m_Size = size; m_LOL = false; m_PlaneList = new List <int>(); uint node = file.Read32(offset); if ((node & 0x80000000) != 0) { uint lolz = baseoffset + (node & 0x7FFFFFFF) + 2; int n = 0; string lmao = ""; for (; ;) { ushort p = file.Read16(lolz); if (p == 0) { break; } else if (p == 37) { m_LOL = true; } m_PlaneList.Add(p - 1); lmao += (p - 1).ToString() + " "; lolz += 2; n++; } if (n > maxkids) { maxkids = n; } //if (m_LOL) // MessageBox.Show(lmao); m_NumPlanes = n; OctreeNode.m_List.Add(this); } else { uint parentoffset = baseoffset + node; uint child0offset = parentoffset; size /= 2f; for (int z = 0; z < 2; z++) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { new OctreeNode(file, child0offset, parentoffset, pos + new Vector3(size.X * x, size.Y * y, size.Z * z), size); parentoffset += 4; } } } } }
public byte[] m_Reserved; // unused, 0s (16) public SDATHeader(NitroFile sdat) { m_Type = sdat.ReadBlock(0x00, 4); m_Magic = sdat.Read32(0x04); m_FileSize = sdat.Read32(0x08); m_Size = sdat.Read16(0x0C); m_Block = sdat.Read16(0x0E); m_SymbolOffset = sdat.Read32(0x10); m_SymbolSize = sdat.Read32(0x14); m_InfoOffset = sdat.Read32(0x18); m_InfoSize = sdat.Read32(0x1C); m_FatOffset = sdat.Read32(0x20); m_FatSize = sdat.Read32(0x24); m_FileBlockOffset = sdat.Read32(0x28); m_FileBlockSize = sdat.Read32(0x2C); m_Reserved = sdat.ReadBlock(0x30, 16); }
public byte[] m_Type; // 'SDAT' (4) #endregion Fields #region Constructors public SDATHeader(NitroFile sdat) { m_Type = sdat.ReadBlock(0x00, 4); m_Magic = sdat.Read32(0x04); m_FileSize = sdat.Read32(0x08); m_Size = sdat.Read16(0x0C); m_Block = sdat.Read16(0x0E); m_SymbolOffset = sdat.Read32(0x10); m_SymbolSize = sdat.Read32(0x14); m_InfoOffset = sdat.Read32(0x18); m_InfoSize = sdat.Read32(0x1C); m_FatOffset = sdat.Read32(0x20); m_FatSize = sdat.Read32(0x24); m_FileBlockOffset = sdat.Read32(0x28); m_FileBlockSize = sdat.Read32(0x2C); m_Reserved = sdat.ReadBlock(0x30, 16); }
public SDATInfoPLAYER(NitroFile sdat, uint offset) { m_Offset = offset; m_SequenceMax = sdat.Read8(m_Offset + 0x00); m_Padding = sdat.Read8(m_Offset + 0x01); m_AllocChannelBitFlag = sdat.Read16(m_Offset + 0x02); m_HeapSize = sdat.Read32(m_Offset + 0x04); }
/* Value Type * 0x0700 SEQ * 0x0803 SEQARC * 0x0601 BANK * 0x0402 WAVEARC * * m_Index is the entry number in the relevant Record (SEQ/SEQARC/BANK/WAVEARC). */ public GroupEntry(NitroFile sdat, uint offset) { m_Offset = offset; m_Type = sdat.Read8(m_Offset + 0x00); m_LoadFlag = sdat.Read8(m_Offset + 0x01); m_Padding = sdat.Read16(m_Offset + 0x02); m_Index = sdat.Read32(m_Offset + 0x04); }
public SDATInfoBANK(NitroFile sdat, uint offset) { m_Offset = offset; m_FileID = sdat.Read32(m_Offset + 0x00); m_WaveArc = new ushort[4]; for (int i = 0; i < 4; i++) { m_WaveArc[i] = sdat.Read16(m_Offset + 0x04 + (uint)(i * 2)); } }
public SDATInfoWAVEARC(NitroFile sdat, uint offset) { m_Offset = offset; uint num = sdat.Read32(m_Offset + 0x00); m_FileID = (num & 16777215u); m_Flag = (byte)(num >> 24); //er.Write((uint)((long)((long)this.flags << 24) | (long)((ulong)(this.fileID & 16777215u)))); }
public SDATInfoGROUP(NitroFile sdat, uint offset) { m_Offset = offset; m_Count = sdat.Read32(m_Offset + 0x00); m_GroupEntries = new GroupEntry[m_Count]; for (int i = 0; i < m_Count; i++) { m_GroupEntries[i] = new GroupEntry(sdat, m_Offset + 0x04 + (uint)(i * 8)); } }
public SDATInfoSEQ(NitroFile sdat, uint offset) { m_File = sdat; m_Offset = offset; m_FileID = sdat.Read32(m_Offset + 0x00); m_Bank = sdat.Read16(m_Offset + 0x04); m_Volume = sdat.Read8(m_Offset + 0x06); m_ChannelPriority = sdat.Read8(m_Offset + 0x07); m_PlayerPriority = sdat.Read8(m_Offset + 0x08); m_PlayerNumber = sdat.Read8(m_Offset + 0x09); m_Unknown2 = sdat.ReadBlock(m_Offset + 0x0A, 2); }
public SDATInfoSTREAM(NitroFile sdat, uint offset) { m_Offset = offset; m_FileID = sdat.Read32(m_Offset + 0x00); m_Volume = sdat.Read8(m_Offset + 0x04); m_PlayerPriority = sdat.Read8(m_Offset + 0x05); m_PlayerNumber = sdat.Read8(m_Offset + 0x06); m_Reserved = new byte[5]; for (int i = 0; i < 5; i++) { m_Reserved[i] = sdat.Read8(m_Offset + 0x07 + (uint)(i)); } }
private void WriteChanges() { NitroFile kclFile = m_KCL.m_File; uint planeStart = (kclFile.Read32(8)); planeStart += (uint)(0x10); for (int i = 0; i < m_Planes.Count; i++) { uint posColType = (uint)(planeStart + (i * 16) + 0x0E); //Get the address of this plane's Collision Type variable kclFile.Write16(posColType, (ushort)m_Planes[i].type); //Write the new value to file } kclFile.SaveChanges(); }
public void LoadTexture() { //Console.WriteLine($"offset = 0x{Convert.ToString(offset, 16)}"); if (m_ParticleTexFile.Read32(0x0) != 0x53505420) { MessageBox.Show(string.Format("This SPT file is invalid."), "Bad texture"); Close(); return; } uint flags = m_ParticleTexFile.Read32(0x04); uint texelArrSize = m_ParticleTexFile.Read32(0x08); uint palOffset = m_ParticleTexFile.Read32(0x0c); uint palSize = m_ParticleTexFile.Read32(0x10); uint totalSize = m_ParticleTexFile.Read32(0x1c); byte[] texels = m_ParticleTexFile.ReadBlock(0x20, texelArrSize); byte[] palette = m_ParticleTexFile.ReadBlock(palOffset, palSize); int width = 1 << (((int)flags >> 4 & 0xf) + 3); int height = 1 << (((int)flags >> 8 & 0xf) + 3); bool color0Transp = ((flags & 0x8) | (flags & 0x10000)) != 0; int type = (int)flags & 0x7; Particle.Texture.RepeatMode repeatX = (flags & 0x4000) != 0 ? Particle.Texture.RepeatMode.FLIP : (flags & 0x1000) != 0 ? Particle.Texture.RepeatMode.REPEAT : Particle.Texture.RepeatMode.CLAMP; Particle.Texture.RepeatMode repeatY = (flags & 0x8000) != 0 ? Particle.Texture.RepeatMode.FLIP : (flags & 0x2000) != 0 ? Particle.Texture.RepeatMode.REPEAT : Particle.Texture.RepeatMode.CLAMP; m_Texture = new Particle.Texture(texels, palette, width, height, (byte)(color0Transp ? 1 : 0), type, repeatX, repeatY, 0); }
public KCL(NitroFile file) { m_File = file; m_Planes = new List<ColFace>(); m_PointsSectionOffset = m_File.Read32(0x00); m_NormalsSectionOffset = m_File.Read32(0x04); m_PlanesSectionOffset = m_File.Read32(0x08); m_OctreeSectionOffset = m_File.Read32(0x0C); int planeid = 0; for (uint offset = m_PlanesSectionOffset + 0x10; offset < m_OctreeSectionOffset; offset += 0x10) { uint length = m_File.Read32(offset); ushort pt_id = m_File.Read16(offset + 0x04); int pt_x = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id*12) )); int pt_y = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id*12) + 4)); int pt_z = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id*12) + 8)); ushort nr_id = m_File.Read16(offset + 0x06); short nr_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id*6) )); short nr_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id*6) + 2)); short nr_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id*6) + 4)); ushort d1_id = m_File.Read16(offset + 0x08); short d1_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id*6) )); short d1_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id*6) + 2)); short d1_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id*6) + 4)); ushort d2_id = m_File.Read16(offset + 0x0A); short d2_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id*6) )); short d2_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id*6) + 2)); short d2_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id*6) + 4)); ushort d3_id = m_File.Read16(offset + 0x0C); short d3_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id*6) )); short d3_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id*6) + 2)); short d3_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id*6) + 4)); ColFace plane = new ColFace((float)(length / 65536000f), new Vector3((float)pt_x / 64000f, (float)pt_y / 64000f, (float)pt_z / 64000f), new Vector3((float)nr_x / 1024f, (float)nr_y / 1024f, (float)nr_z / 1024f), new Vector3((float)d1_x / 1024f, (float)d1_y / 1024f, (float)d1_z / 1024f), new Vector3((float)d2_x / 1024f, (float)d2_y / 1024f, (float)d2_z / 1024f), new Vector3((float)d3_x / 1024f, (float)d3_y / 1024f, (float)d3_z / 1024f), m_File.Read16(offset + 0x0E)); /* if (planeid == 31) MessageBox.Show(string.Format("PLANE 32:\n{0}\n{1}\n{2}\n\n{3}\n{4}\n{5}\n\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}", d1_x, d1_y, d1_z, d2_x, d2_y, d2_z, plane.m_Position, plane.m_Normal, plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Length));*/ planeid++; /* if (Math.Abs(plane.m_Dir1.Length - 1f) > 0.0001f || Math.Abs(plane.m_Dir2.Length - 1f) > 0.0001f || Math.Abs(plane.m_Dir3.Length - 1f) > 0.0001f || Math.Abs(plane.m_Normal.Length - 1f) > 0.0001f || plane.m_Length < 0f) MessageBox.Show(string.Format("WRONG PLANE | {0} | {1} | {2} | {3} | {4}", plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); if (plane.m_Dir1.Length < 0.001f || plane.m_Dir2.Length < 0.001f || plane.m_Dir3.Length < 0.001f || plane.m_Normal.Length < 0.001f || Math.Abs(plane.m_Length) < 0.001f) MessageBox.Show(string.Format("ZERO PLANE | {0} | {1} | {2} | {3} | {4}", plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); Vector3 lol1 = Vector3.Cross(plane.m_Dir1, plane.m_Normal); float lol1len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol1, plane.m_Dir3)))); Vector3 lol2 = Vector3.Cross(plane.m_Normal, plane.m_Dir2); float lol2len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol2, plane.m_Dir3)))); if (Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol1, lol1len)) || Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol2, lol2len))) MessageBox.Show(string.Format("WEIRD PLANE {5:X8} | {0} | {1} | {2} | {3} | {4}\n{6} | {7} / cos(acos({8})) = cos({9}) = {10}", plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Normal, plane.m_Length, offset, lol2, plane.m_Length, Vector3.Dot(lol2, plane.m_Dir3), Math.Acos(Vector3.Dot(lol2, plane.m_Dir3)), Math.Cos(Math.Acos(Vector3.Dot(lol2, plane.m_Dir3))))); */ m_Planes.Add(plane); } OctreeNode.maxkids = 0; int shift = (int)m_File.Read32(0x2C); Vector3 octreestart = new Vector3((float)(int)m_File.Read32(0x14) / 64000f, (float)(int)m_File.Read32(0x18) / 64000f, (float)(int)m_File.Read32(0x1C) / 64000f); float _cubesize = (float)(1 << shift) / 1024f; Vector3 cubesize = new Vector3(_cubesize, _cubesize, _cubesize); Vector3 octreesize = new Vector3((~m_File.Read32(0x20) >> shift) + 1, (~m_File.Read32(0x24) >> shift) + 1, (~m_File.Read32(0x28) >> shift) + 1); OctreeNode.m_List = new List<OctreeNode>(); uint loloffset = m_OctreeSectionOffset; for (int z = 0; z < octreesize.Z; z++) for (int y = 0; y < octreesize.Y; y++) for (int x = 0; x < octreesize.X; x++) { new OctreeNode(m_File, m_OctreeSectionOffset, loloffset, octreestart + new Vector3(cubesize.X * x, cubesize.Y * y, cubesize.Z * z), cubesize); loloffset += 4; } //MessageBox.Show(OctreeNode.m_List.Count.ToString()); }
public BMD(NitroFile file) { m_File = file; m_FileName = file.m_Name; /* if (m_File.m_ID == 741) * lolol = true; * else*/ lolol = false; // Keep a list of pointers so it's easier to add/remove entries, space etc. m_PointerList = new List <PointerReference>(); m_ScaleFactor = (float)(1 << (int)m_File.Read32(0x0)); // ModelChunk refers to Bone m_NumModelChunks = m_File.Read32(0x04); m_ModelChunksOffset = m_File.Read32(0x08); AddPointer(0x08); for (int i = 0; i < m_NumModelChunks; i++) { AddPointer((uint)(m_ModelChunksOffset + (i * 64) + 0x04)); AddPointer((uint)(m_ModelChunksOffset + (i * 64) + 0x34)); AddPointer((uint)(m_ModelChunksOffset + (i * 64) + 0x38)); } // PolyChunk refers to Display List m_NumPolyChunks = m_File.Read32(0x0C); m_PolyChunksOffset = m_File.Read32(0x10); AddPointer(0x10); for (int i = 0; i < m_NumPolyChunks; i++) { // Offset to Display List within Display List entries AddPointer((uint)(m_PolyChunksOffset + (i * 8) + 4)); // Offsets within the Display List 16 byte headers AddPointer(m_File.Read32((uint)(m_PolyChunksOffset + (i * 8) + 4)) + 0x04); AddPointer(m_File.Read32((uint)(m_PolyChunksOffset + (i * 8) + 4)) + 0x0C); } m_NumTexChunks = m_File.Read32(0x14); m_TexChunksOffset = m_File.Read32(0x18); m_TextureIDs = new Dictionary <string, uint>(); AddPointer(0x18); for (int i = 0; i < m_NumTexChunks; i++) { AddPointer((uint)(m_TexChunksOffset + (i * 20) + 0)); AddPointer((uint)(m_TexChunksOffset + (i * 20) + 4)); m_TextureIDs.Add(m_File.ReadString(m_File.Read32((uint)(m_TexChunksOffset + (20 * i))), 0), (uint)i); } m_NumPalChunks = m_File.Read32(0x1C); m_PalChunksOffset = m_File.Read32(0x20); m_PaletteIDs = new Dictionary <string, uint>(); AddPointer(0x20); for (int i = 0; i < m_NumPalChunks; i++) { AddPointer((uint)(m_PalChunksOffset + (i * 16) + 0)); AddPointer((uint)(m_PalChunksOffset + (i * 16) + 4)); m_PaletteIDs.Add(m_File.ReadString(m_File.Read32((uint)(m_PalChunksOffset + (16 * i))), 0), (uint)i); } m_NumMatChunks = m_File.Read32(0x24); m_MatChunksOffset = m_File.Read32(0x28); AddPointer(0x28); for (int i = 0; i < m_NumMatChunks; i++) { AddPointer((uint)(m_MatChunksOffset + (i * 48) + 0)); } m_BoneMapOffset = m_File.Read32(0x2C); AddPointer(0x2C); m_Textures = new Dictionary <string, NitroTexture>(); m_ModelChunks = new ModelChunk[m_NumModelChunks]; for (uint c = 0; c < m_NumModelChunks; c++) { ModelChunk mdchunk = new ModelChunk(this); m_ModelChunks[c] = mdchunk; uint mdchunkoffset = m_ModelChunksOffset + (c * 64); mdchunk.m_ID = m_File.Read32(mdchunkoffset); mdchunk.m_Name = m_File.ReadString(m_File.Read32(mdchunkoffset + 0x04), 0); // transforms part { int xscale = (int)m_File.Read32(mdchunkoffset + 0x10); int yscale = (int)m_File.Read32(mdchunkoffset + 0x14); int zscale = (int)m_File.Read32(mdchunkoffset + 0x18); short xrot = (short)m_File.Read16(mdchunkoffset + 0x1C); short yrot = (short)m_File.Read16(mdchunkoffset + 0x1E); short zrot = (short)m_File.Read16(mdchunkoffset + 0x20); int xtrans = (int)m_File.Read32(mdchunkoffset + 0x24); int ytrans = (int)m_File.Read32(mdchunkoffset + 0x28); int ztrans = (int)m_File.Read32(mdchunkoffset + 0x2C); mdchunk.m_Scale = new Vector3((float)xscale / 4096.0f, (float)yscale / 4096.0f, (float)zscale / 4096.0f); mdchunk.m_Rotation = new Vector3(((float)xrot * (float)Math.PI) / 2048.0f, ((float)yrot * (float)Math.PI) / 2048.0f, ((float)zrot * (float)Math.PI) / 2048.0f); mdchunk.m_Translation = new Vector3((float)xtrans / 4096.0f, (float)ytrans / 4096.0f, (float)ztrans / 4096.0f); mdchunk.m_Transform = Helper.SRTToMatrix(mdchunk.m_Scale, mdchunk.m_Rotation, mdchunk.m_Translation); // Used when exporting bones mdchunk.m_20_12Scale = new uint[] { (uint)xscale, (uint)yscale, (uint)zscale }; mdchunk.m_4_12Rotation = new ushort[] { (ushort)xrot, (ushort)yrot, (ushort)zrot }; mdchunk.m_20_12Translation = new uint[] { (uint)xtrans, (uint)ytrans, (uint)ztrans }; // if the chunk has a parent, apply the parent's transform to the chunk's transform. // we don't need to go further than one level because the paren't transform already // went through its parents' transforms. short parent_offset = (short)m_File.Read16(mdchunkoffset + 0x8); if (parent_offset < 0) { int parentchunkid = (int)(c + parent_offset); Matrix4.Mult(ref mdchunk.m_Transform, ref m_ModelChunks[parentchunkid].m_Transform, out mdchunk.m_Transform); } mdchunk.m_ParentOffset = parent_offset; } // If 0x0A is set to 1 the bone has children, if 0 it doesn't mdchunk.m_HasChildren = (m_File.Read16(mdchunkoffset + 0x0A) == 1); mdchunk.m_SiblingOffset = (short)(m_File.Read16(mdchunkoffset + 0x0C)); uint flags = m_File.Read32(mdchunkoffset + 0x3C); mdchunk.m_Billboard = ((flags & 0x1) == 0x1); uint numpairs = m_File.Read32(mdchunkoffset + 0x30); uint matlist = m_File.Read32(mdchunkoffset + 0x34); uint polylist = m_File.Read32(mdchunkoffset + 0x38); mdchunk.m_MatGroups = new MaterialGroup[numpairs]; for (uint i = 0; i < numpairs; i++) { MaterialGroup matgroup = new MaterialGroup(); mdchunk.m_MatGroups[i] = matgroup; byte matID = m_File.Read8(matlist + i); byte polyID = m_File.Read8(polylist + i); uint mchunkoffset = (uint)(m_MatChunksOffset + (matID * 48)); matgroup.m_ID = matID; matgroup.m_Name = m_File.ReadString(m_File.Read32(mchunkoffset), 0); uint texid = m_File.Read32(mchunkoffset + 0x04); uint palid = m_File.Read32(mchunkoffset + 0x08); matgroup.m_TexParams = m_File.Read32(mchunkoffset + 0x20); matgroup.m_PolyAttribs = m_File.Read32(mchunkoffset + 0x24); matgroup.m_DifAmbColors = m_File.Read32(mchunkoffset + 0x28); matgroup.m_SpeEmiColors = m_File.Read32(mchunkoffset + 0x2C); if ((matgroup.m_PolyAttribs & 0x30) == 0x10) { matgroup.m_TexEnvMode = TextureEnvMode.Decal; } else { matgroup.m_TexEnvMode = TextureEnvMode.Modulate; } switch (matgroup.m_PolyAttribs & 0xC0) { case 0x00: matgroup.m_CullMode = CullFaceMode.FrontAndBack; break; case 0x40: matgroup.m_CullMode = CullFaceMode.Front; break; case 0x80: matgroup.m_CullMode = CullFaceMode.Back; break; } matgroup.m_DiffuseColor = Helper.BGR15ToColor((ushort)matgroup.m_DifAmbColors); matgroup.m_AmbientColor = Helper.BGR15ToColor((ushort)(matgroup.m_DifAmbColors >> 16)); matgroup.m_SpecularColor = Helper.BGR15ToColor((ushort)matgroup.m_SpeEmiColors); matgroup.m_EmissionColor = Helper.BGR15ToColor((ushort)(matgroup.m_SpeEmiColors >> 16)); switch (matgroup.m_TexParams >> 30) { case 0: matgroup.m_TexCoordScale = new Vector2(1.0f, 1.0f); matgroup.m_TexCoordRot = 0.0f; matgroup.m_TexCoordTrans = new Vector2(0.0f, 0.0f); break; case 1: { int sscale = (int)m_File.Read32(mchunkoffset + 0x0C); int tscale = (int)m_File.Read32(mchunkoffset + 0x10); short trot = (short)m_File.Read16(mchunkoffset + 0x14); int strans = (int)m_File.Read32(mchunkoffset + 0x18); int ttrans = (int)m_File.Read32(mchunkoffset + 0x1C); matgroup.m_TexCoordScale = new Vector2((float)sscale / 4096.0f, (float)tscale / 4096.0f); matgroup.m_TexCoordRot = ((float)trot * (float)Math.PI) / 2048.0f; matgroup.m_TexCoordTrans = new Vector2((float)strans / 4096.0f, (float)ttrans / 4096.0f); } break; case 2: goto case 1; case 3: goto case 1; default: break; // throw new Exception(String.Format("BMD: unsupported texture coord transform mode {0}", matgroup.m_TexParams >> 30)); } if (texid != 0xFFFFFFFF) { matgroup.m_Texture = ReadTexture(texid, palid); matgroup.m_TexParams |= matgroup.m_Texture.m_DSTexParam; } else { matgroup.m_Texture = null; } uint pchunkoffset = m_File.Read32((uint)(m_PolyChunksOffset + (polyID * 8) + 4)); uint dloffset = m_File.Read32(pchunkoffset + 0x0C); uint dlsize = m_File.Read32(pchunkoffset + 0x08); uint numbones = m_File.Read32(pchunkoffset); uint bonesoffset = m_File.Read32(pchunkoffset + 0x04); matgroup.m_BoneIDs = new ushort[numbones]; for (uint b = 0; b < numbones; b++) { byte idx1 = m_File.Read8(bonesoffset + b); matgroup.m_BoneIDs[b] = m_File.Read16((uint)(m_BoneMapOffset + (2 * idx1))); } matgroup.m_Geometry = new List <VertexList>(); m_CurVertex.m_Position = new Vector3(0, 0, 0); m_CurVertex.m_TexCoord = null; m_CurVertex.m_Normal = null; if ((matgroup.m_PolyAttribs & 0x8000) != 0x8000) { byte alpha = (byte)((matgroup.m_PolyAttribs >> 16) & 0x1F); alpha |= (byte)(alpha >> 5); matgroup.m_Alpha = alpha; } if ((matgroup.m_DifAmbColors & 0x8000) == 0x8000) { m_CurVertex.m_Color = Color.FromArgb(matgroup.m_Alpha << 3, matgroup.m_DiffuseColor); } else { m_CurVertex.m_Color = Color.Black; } m_CurVertex.m_MatrixID = 0; uint dlend = dloffset + dlsize; for (uint pos = dloffset; pos < dlend;) { byte cmd1 = m_File.Read8(pos++); byte cmd2 = m_File.Read8(pos++); byte cmd3 = m_File.Read8(pos++); byte cmd4 = m_File.Read8(pos++); ProcessGXCommand(matgroup, cmd1, ref pos); ProcessGXCommand(matgroup, cmd2, ref pos); ProcessGXCommand(matgroup, cmd3, ref pos); ProcessGXCommand(matgroup, cmd4, ref pos); } } } foreach (ModelChunk mdchunk in m_ModelChunks) { foreach (MaterialGroup matgroup in mdchunk.m_MatGroups) { matgroup.m_BoneMatrices = new Matrix4[matgroup.m_BoneIDs.Length]; for (uint b = 0; b < matgroup.m_BoneIDs.Length; b++) { matgroup.m_BoneMatrices[b] = m_ModelChunks[matgroup.m_BoneIDs[b]].m_Transform; } } } int index = 0; foreach (KeyValuePair <string, uint> entry in m_TextureIDs) { if (!m_Textures.ContainsKey(entry.Key)) { Console.WriteLine("NOT IN TEXTURES: " + entry.Key); uint palID = Math.Min(m_PaletteIDs.ElementAt(index).Value, (uint)m_PaletteIDs.Count - 1); ReadTexture(entry.Value, palID); } index++; } }
char[] m_Type; // 'INFO' #endregion Fields #region Constructors public SDATInfo(NitroFile sdat, uint offset) { m_Offset = offset; m_Type = sdat.ReadString(m_Offset + 0x00, 4).ToCharArray(); m_Size = sdat.Read32(m_Offset + 0x04); m_RecordOffset = new uint[8]; for (int i = 0; i < 8; i++) m_RecordOffset[i] = sdat.Read32(m_Offset + 0x08 + (uint)(i * 4)); m_Reserved = sdat.ReadBlock(m_Offset + 0x28, 24); m_Records = new SDATInfoRecord[8]; for (int i = 0; i < 8; i++) { m_Records[i] = new SDATInfoRecord(sdat, m_Offset + m_RecordOffset[i]); } m_Records0SEQ = new SDATInfoSEQ[m_Records[0].m_Count]; for (int i = 0; i < m_Records[0].m_Count; i++) { m_Records0SEQ[i] = new SDATInfoSEQ(sdat, m_Offset + m_Records[0].m_EntryOffset[i]); } m_Records1SEQARC = new SDATInfoSEQARC[m_Records[1].m_Count]; for (int i = 0; i < m_Records[1].m_Count; i++) { m_Records1SEQARC[i] = new SDATInfoSEQARC(sdat, m_Offset + m_Records[1].m_EntryOffset[i]); } m_Records2BANK = new SDATInfoBANK[m_Records[2].m_Count]; for (int i = 0; i < m_Records[2].m_Count; i++) { m_Records2BANK[i] = new SDATInfoBANK(sdat, m_Offset + m_Records[2].m_EntryOffset[i]); } m_Records3WAVEARC = new SDATInfoWAVEARC[m_Records[3].m_Count]; for (int i = 0; i < m_Records[3].m_Count; i++) { m_Records3WAVEARC[i] = new SDATInfoWAVEARC(sdat, m_Offset + m_Records[3].m_EntryOffset[i]); } m_Records4PLAYER = new SDATInfoPLAYER[m_Records[4].m_Count]; for (int i = 0; i < m_Records[4].m_Count; i++) { m_Records4PLAYER[i] = new SDATInfoPLAYER(sdat, m_Offset + m_Records[4].m_EntryOffset[i]); } m_Records5GROUP = new SDATInfoGROUP[m_Records[5].m_Count]; for (int i = 0; i < m_Records[5].m_Count; i++) { m_Records5GROUP[i] = new SDATInfoGROUP(sdat, m_Offset + m_Records[5].m_EntryOffset[i]); } m_Records6PLAYER2 = new SDATInfoPLAYER2[m_Records[6].m_Count]; for (int i = 0; i < m_Records[6].m_Count; i++) { m_Records6PLAYER2[i] = new SDATInfoPLAYER2(sdat, m_Offset + m_Records[6].m_EntryOffset[i]); } m_Records7STREAM = new SDATInfoSTREAM[m_Records[7].m_Count]; for (int i = 0; i < m_Records[7].m_Count; i++) { m_Records7STREAM[i] = new SDATInfoSTREAM(sdat, m_Offset + m_Records[7].m_EntryOffset[i]); } }
public SDATInfoSEQARC(NitroFile sdat, uint offset) { m_Offset = offset; m_FileID = sdat.Read32(m_Offset + 0x00); }
public SDATInfoRecord(NitroFile sdat, uint offset) { m_Offset = offset; m_Count = sdat.Read32(m_Offset); m_EntryOffset = new uint[m_Count]; for (int i = 0; i < m_Count; i++) m_EntryOffset[i] = sdat.Read32(m_Offset + 0x04 + (uint)(i * 4)); }
public SDATInfoSTREAM(NitroFile sdat, uint offset) { m_Offset = offset; m_FileID = sdat.Read32(m_Offset + 0x00); m_Volume = sdat.Read8(m_Offset + 0x04); m_PlayerPriority = sdat.Read8(m_Offset + 0x05); m_PlayerNumber = sdat.Read8(m_Offset + 0x06); m_Reserved = new byte[5]; for (int i = 0; i < 5; i++) m_Reserved[i] = sdat.Read8(m_Offset + 0x07 + (uint)(i)); }
public OctreeNode(NitroFile file, uint baseoffset, uint offset, Vector3 pos, Vector3 size) { m_Pos = pos; m_Size = size; m_LOL = false; m_PlaneList = new List<int>(); uint node = file.Read32(offset); if ((node & 0x80000000) != 0) { uint lolz = baseoffset + (node & 0x7FFFFFFF) + 2; int n = 0; string lmao = ""; for (; ; ) { ushort p = file.Read16(lolz); if (p == 0) break; else if (p == 37) m_LOL = true; m_PlaneList.Add(p - 1); lmao += (p - 1).ToString() + " "; lolz += 2; n++; } if (n > maxkids) maxkids = n; //if (m_LOL) // MessageBox.Show(lmao); m_NumPlanes = n; OctreeNode.m_List.Add(this); } else { uint parentoffset = baseoffset + node; uint child0offset = parentoffset; size /= 2f; for (int z = 0; z < 2; z++) for (int y = 0; y < 2; y++) for (int x = 0; x < 2; x++) { new OctreeNode(file, child0offset, parentoffset, pos + new Vector3(size.X * x, size.Y * y, size.Z * z), size); parentoffset += 4; } } }
public void ReadStrings(String fileName) { file = Program.m_ROM.GetFileFromName(fileName); inf1size = file.Read32(0x24); ushort numentries = file.Read16(0x28); m_MsgData = new string[numentries]; m_StringLengths = new int[numentries]; m_ShortVersions = new string[numentries]; m_FileSize = file.Read32(0x08); m_StringHeaderAddr = new uint[numentries]; m_StringHeaderData = new uint[numentries]; m_DAT1Start = 0x20 + inf1size + 0x08; for (int i = 0; i < numentries; i++) { m_StringHeaderAddr[i] = (uint)(0x20 + 0x10 + (i * 8)); m_StringHeaderData[i] = file.Read32(m_StringHeaderAddr[i]); } lbxMsgList.Items.Clear();//Reset list of messages lbxMsgList.BeginUpdate();// Only draw when EndUpdate is called, much faster, expecially for Mono for (int i = 0; i < m_MsgData.Length; i++) { uint straddr = file.Read32((uint)(0x30 + i * 8)); straddr += 0x20 + inf1size + 0x8; int length = 0; string thetext = ""; for (; ; ) { byte cur; try { cur = file.Read8(straddr); } catch { break; } straddr++; length++; char thechar = '\0'; /*if ((cur >= 0x00) && (cur <= 0x09)) thechar = (char)('0' + cur); else if ((cur >= 0x0A) && (cur <= 0x23)) thechar = (char)('A' + cur - 0x0A); else if ((cur >= 0x2D) && (cur <= 0x46)) thechar = (char)('a' + cur - 0x2D); else if ((cur >= 0x50) && (cur <= 0xCF))//Extended ASCII Characters thechar = (char)(0x30 + cur);*/ // Some characters are two bytes long, can skip the second if (langNames[langIndex] == "jpn") { if (JAP_CHARS.GetFirstToSecond().ContainsKey(cur)) { thetext += JAP_CHARS.GetByFirst(cur); straddr += (JAP_SIZES[JAP_CHARS.GetByFirst(cur)] - 1); length += (int)(JAP_SIZES[JAP_CHARS.GetByFirst(cur)] - 1); } } else { if ((cur >= 0x00 && cur <= 0x4F) || (cur >= 0xEE && cur <= 0xFB)) { thetext += BASIC_EUR_US_CHARS.GetByFirst(cur); straddr += (BASIC_EUR_US_SIZES[BASIC_EUR_US_CHARS.GetByFirst(cur)] - 1); length += (int)(BASIC_EUR_US_SIZES[BASIC_EUR_US_CHARS.GetByFirst(cur)] - 1); } else if (cur >= 0x50 && cur <= 0xCF) { thetext += EXTENDED_ASCII_CHARS.GetByFirst(cur); straddr += (EXTENDED_ASCII_SIZES[EXTENDED_ASCII_CHARS.GetByFirst(cur)] - 1); length += (int)(EXTENDED_ASCII_SIZES[EXTENDED_ASCII_CHARS.GetByFirst(cur)] - 1); } } if (thechar != '\0') thetext += thechar; else if (cur == 0xFD) thetext += "\r\n"; else if (cur == 0xFF) break; else if (cur == 0xFE)// Special Character { int len = file.Read8(straddr); thetext += "[\\r]"; thetext += String.Format("{0:X2}", cur); for (int spec = 0; spec < len - 1; spec++) { thetext += String.Format("{0:X2}", file.Read8((uint)(straddr + spec))); } length += (len - 1);// Already increased by 1 at start straddr += (uint)(len - 1); } } m_MsgData[i] = thetext; m_StringLengths[i] = length; m_ShortVersions[i] = ShortVersion(m_MsgData[i], i); lbxMsgList.Items.Add(m_ShortVersions[i]); btnImport.Enabled = true; btnExport.Enabled = true; } lbxMsgList.EndUpdate(); }
public KCL(NitroFile file) { m_File = file; m_Planes = new List <ColFace>(); m_PointsSectionOffset = m_File.Read32(0x00); m_NormalsSectionOffset = m_File.Read32(0x04); m_PlanesSectionOffset = m_File.Read32(0x08); m_OctreeSectionOffset = m_File.Read32(0x0C); int planeid = 0; for (uint offset = m_PlanesSectionOffset + 0x10; offset < m_OctreeSectionOffset; offset += 0x10) { uint length = m_File.Read32(offset); ushort pt_id = m_File.Read16(offset + 0x04); int pt_x = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id * 12))); int pt_y = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id * 12) + 4)); int pt_z = (int)m_File.Read32((uint)(m_PointsSectionOffset + (pt_id * 12) + 8)); ushort nr_id = m_File.Read16(offset + 0x06); short nr_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id * 6))); short nr_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id * 6) + 2)); short nr_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (nr_id * 6) + 4)); ushort d1_id = m_File.Read16(offset + 0x08); short d1_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id * 6))); short d1_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id * 6) + 2)); short d1_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d1_id * 6) + 4)); ushort d2_id = m_File.Read16(offset + 0x0A); short d2_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id * 6))); short d2_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id * 6) + 2)); short d2_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d2_id * 6) + 4)); ushort d3_id = m_File.Read16(offset + 0x0C); short d3_x = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id * 6))); short d3_y = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id * 6) + 2)); short d3_z = (short)m_File.Read16((uint)(m_NormalsSectionOffset + (d3_id * 6) + 4)); ColFace plane = new ColFace((float)(length / 65536000f), new Vector3((float)pt_x / 64000f, (float)pt_y / 64000f, (float)pt_z / 64000f), new Vector3((float)nr_x / 1024f, (float)nr_y / 1024f, (float)nr_z / 1024f), new Vector3((float)d1_x / 1024f, (float)d1_y / 1024f, (float)d1_z / 1024f), new Vector3((float)d2_x / 1024f, (float)d2_y / 1024f, (float)d2_z / 1024f), new Vector3((float)d3_x / 1024f, (float)d3_y / 1024f, (float)d3_z / 1024f), m_File.Read16(offset + 0x0E)); /* if (planeid == 31) * MessageBox.Show(string.Format("PLANE 32:\n{0}\n{1}\n{2}\n\n{3}\n{4}\n{5}\n\n{6}\n{7}\n{8}\n{9}\n{10}\n{11}", * d1_x, d1_y, d1_z, * d2_x, d2_y, d2_z, * plane.m_Position, plane.m_Normal, plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Length));*/ planeid++; /* if (Math.Abs(plane.m_Dir1.Length - 1f) > 0.0001f || Math.Abs(plane.m_Dir2.Length - 1f) > 0.0001f || * Math.Abs(plane.m_Dir3.Length - 1f) > 0.0001f || Math.Abs(plane.m_Normal.Length - 1f) > 0.0001f || * plane.m_Length < 0f) * MessageBox.Show(string.Format("WRONG PLANE | {0} | {1} | {2} | {3} | {4}", * plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); * * if (plane.m_Dir1.Length < 0.001f || plane.m_Dir2.Length < 0.001f || * plane.m_Dir3.Length < 0.001f || plane.m_Normal.Length < 0.001f || * Math.Abs(plane.m_Length) < 0.001f) * MessageBox.Show(string.Format("ZERO PLANE | {0} | {1} | {2} | {3} | {4}", * plane.m_Dir1.Length, plane.m_Dir2.Length, plane.m_Dir3.Length, plane.m_Normal.Length, plane.m_Length)); * * Vector3 lol1 = Vector3.Cross(plane.m_Dir1, plane.m_Normal); * float lol1len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol1, plane.m_Dir3)))); * Vector3 lol2 = Vector3.Cross(plane.m_Normal, plane.m_Dir2); * float lol2len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f,Vector3.Dot(lol2, plane.m_Dir3)))); * if (Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol1, lol1len)) || * Helper.VectorsEqual(plane.m_Position, Vector3.Multiply(lol2, lol2len))) * MessageBox.Show(string.Format("WEIRD PLANE {5:X8} | {0} | {1} | {2} | {3} | {4}\n{6} | {7} / cos(acos({8})) = cos({9}) = {10}", * plane.m_Dir1, plane.m_Dir2, plane.m_Dir3, plane.m_Normal, plane.m_Length, * offset, lol2, plane.m_Length, Vector3.Dot(lol2, plane.m_Dir3), Math.Acos(Vector3.Dot(lol2, plane.m_Dir3)), Math.Cos(Math.Acos(Vector3.Dot(lol2, plane.m_Dir3))))); */ m_Planes.Add(plane); } OctreeNode.maxkids = 0; int shift = (int)m_File.Read32(0x2C); Vector3 octreestart = new Vector3((float)(int)m_File.Read32(0x14) / 64000f, (float)(int)m_File.Read32(0x18) / 64000f, (float)(int)m_File.Read32(0x1C) / 64000f); float _cubesize = (float)(1 << shift) / 1024f; Vector3 cubesize = new Vector3(_cubesize, _cubesize, _cubesize); Vector3 octreesize = new Vector3((~m_File.Read32(0x20) >> shift) + 1, (~m_File.Read32(0x24) >> shift) + 1, (~m_File.Read32(0x28) >> shift) + 1); OctreeNode.m_List = new List <OctreeNode>(); uint loloffset = m_OctreeSectionOffset; for (int z = 0; z < octreesize.Z; z++) { for (int y = 0; y < octreesize.Y; y++) { for (int x = 0; x < octreesize.X; x++) { new OctreeNode(m_File, m_OctreeSectionOffset, loloffset, octreestart + new Vector3(cubesize.X * x, cubesize.Y * y, cubesize.Z * z), cubesize); loloffset += 4; } } } //MessageBox.Show(OctreeNode.m_List.Count.ToString()); }
public BMD(NitroFile file) { m_File = file; m_FileName = file.m_Name; /* if (m_File.m_ID == 741) lolol = true; else*/ lolol = false; // Keep a list of pointers so it's easier to add/remove entries, space etc. m_PointerList = new List<PointerReference>(); m_ScaleFactor = (float)(1 << (int)m_File.Read32(0x0)); // ModelChunk refers to Bone m_NumModelChunks = m_File.Read32(0x04); m_ModelChunksOffset = m_File.Read32(0x08); AddPointer(0x08); for (int i = 0; i < m_NumModelChunks; i++) { AddPointer((uint)(m_ModelChunksOffset + (i * 64) + 0x04)); AddPointer((uint)(m_ModelChunksOffset + (i * 64) + 0x34)); AddPointer((uint)(m_ModelChunksOffset + (i * 64) + 0x38)); } // PolyChunk refers to Display List m_NumPolyChunks = m_File.Read32(0x0C); m_PolyChunksOffset = m_File.Read32(0x10); AddPointer(0x10); for (int i = 0; i < m_NumPolyChunks; i++) { // Offset to Display List within Display List entries AddPointer((uint)(m_PolyChunksOffset + (i * 8) + 4)); // Offsets within the Display List 16 byte headers AddPointer(m_File.Read32((uint)(m_PolyChunksOffset + (i * 8) + 4)) + 0x04); AddPointer(m_File.Read32((uint)(m_PolyChunksOffset + (i * 8) + 4)) + 0x0C); } m_NumTexChunks = m_File.Read32(0x14); m_TexChunksOffset = m_File.Read32(0x18); m_TextureIDs = new Dictionary<string, uint>(); AddPointer(0x18); for (int i = 0; i < m_NumTexChunks; i++) { AddPointer((uint)(m_TexChunksOffset + (i * 20) + 0)); AddPointer((uint)(m_TexChunksOffset + (i * 20) + 4)); m_TextureIDs.Add(m_File.ReadString(m_File.Read32((uint)(m_TexChunksOffset + (20 * i))), 0), (uint)i); } m_NumPalChunks = m_File.Read32(0x1C); m_PalChunksOffset = m_File.Read32(0x20); m_PaletteIDs = new Dictionary<string, uint>(); AddPointer(0x20); for (int i = 0; i < m_NumPalChunks; i++) { AddPointer((uint)(m_PalChunksOffset + (i * 16) + 0)); AddPointer((uint)(m_PalChunksOffset + (i * 16) + 4)); m_PaletteIDs.Add(m_File.ReadString(m_File.Read32((uint)(m_PalChunksOffset + (16 * i))), 0), (uint)i); } m_NumMatChunks = m_File.Read32(0x24); m_MatChunksOffset = m_File.Read32(0x28); AddPointer(0x28); for (int i = 0; i < m_NumMatChunks; i++) { AddPointer((uint)(m_MatChunksOffset + (i * 48) + 0)); } m_BoneMapOffset = m_File.Read32(0x2C); AddPointer(0x2C); m_Textures = new Dictionary<string, Texture>(); m_ModelChunks = new ModelChunk[m_NumModelChunks]; for (uint c = 0; c < m_NumModelChunks; c++) { ModelChunk mdchunk = new ModelChunk(this); m_ModelChunks[c] = mdchunk; uint mdchunkoffset = m_ModelChunksOffset + (c * 64); mdchunk.m_ID = m_File.Read32(mdchunkoffset); mdchunk.m_Name = m_File.ReadString(m_File.Read32(mdchunkoffset + 0x04), 0); // transforms part { int xscale = (int)m_File.Read32(mdchunkoffset + 0x10); int yscale = (int)m_File.Read32(mdchunkoffset + 0x14); int zscale = (int)m_File.Read32(mdchunkoffset + 0x18); short xrot = (short)m_File.Read16(mdchunkoffset + 0x1C); short yrot = (short)m_File.Read16(mdchunkoffset + 0x1E); short zrot = (short)m_File.Read16(mdchunkoffset + 0x20); int xtrans = (int)m_File.Read32(mdchunkoffset + 0x24); int ytrans = (int)m_File.Read32(mdchunkoffset + 0x28); int ztrans = (int)m_File.Read32(mdchunkoffset + 0x2C); mdchunk.m_Scale = new Vector3((float)xscale / 4096.0f, (float)yscale / 4096.0f, (float)zscale / 4096.0f); mdchunk.m_Rotation = new Vector3(((float)xrot * (float)Math.PI) / 2048.0f, ((float)yrot * (float)Math.PI) / 2048.0f, ((float)zrot * (float)Math.PI) / 2048.0f); mdchunk.m_Translation = new Vector3((float)xtrans / 4096.0f, (float)ytrans / 4096.0f, (float)ztrans / 4096.0f); mdchunk.m_Transform = Helper.SRTToMatrix(mdchunk.m_Scale, mdchunk.m_Rotation, mdchunk.m_Translation); // Used when exporting bones mdchunk.m_20_12Scale = new uint[] { (uint)xscale, (uint)yscale, (uint)zscale }; mdchunk.m_4_12Rotation = new ushort[] { (ushort)xrot, (ushort)yrot, (ushort)zrot }; mdchunk.m_20_12Translation = new uint[] { (uint)xtrans, (uint)ytrans, (uint)ztrans }; // if the chunk has a parent, apply the parent's transform to the chunk's transform. // we don't need to go further than one level because the paren't transform already // went through its parents' transforms. short parent_offset = (short)m_File.Read16(mdchunkoffset + 0x8); if (parent_offset < 0) { int parentchunkid = (int)(c + parent_offset); Matrix4.Mult(ref mdchunk.m_Transform, ref m_ModelChunks[parentchunkid].m_Transform, out mdchunk.m_Transform); } mdchunk.m_ParentOffset = parent_offset; } // If 0x0A is set to 1 the bone has children, if 0 it doesn't mdchunk.m_HasChildren = (m_File.Read16(mdchunkoffset + 0x0A) == 1); mdchunk.m_SiblingOffset = (short)(m_File.Read16(mdchunkoffset + 0x0C)); uint flags = m_File.Read32(mdchunkoffset + 0x3C); mdchunk.m_Billboard = ((flags & 0x1) == 0x1); uint numpairs = m_File.Read32(mdchunkoffset + 0x30); uint matlist = m_File.Read32(mdchunkoffset + 0x34); uint polylist = m_File.Read32(mdchunkoffset + 0x38); mdchunk.m_MatGroups = new MaterialGroup[numpairs]; for (uint i = 0; i < numpairs; i++) { MaterialGroup matgroup = new MaterialGroup(); mdchunk.m_MatGroups[i] = matgroup; byte matID = m_File.Read8(matlist + i); byte polyID = m_File.Read8(polylist + i); uint mchunkoffset = (uint)(m_MatChunksOffset + (matID * 48)); matgroup.m_ID = matID; matgroup.m_Name = m_File.ReadString(m_File.Read32(mchunkoffset), 0); uint texid = m_File.Read32(mchunkoffset + 0x04); uint palid = m_File.Read32(mchunkoffset + 0x08); matgroup.m_TexParams = m_File.Read32(mchunkoffset + 0x20); matgroup.m_PolyAttribs = m_File.Read32(mchunkoffset + 0x24); matgroup.m_DifAmbColors = m_File.Read32(mchunkoffset + 0x28); matgroup.m_SpeEmiColors = m_File.Read32(mchunkoffset + 0x2C); if ((matgroup.m_PolyAttribs & 0x30) == 0x10) matgroup.m_TexEnvMode = TextureEnvMode.Decal; else matgroup.m_TexEnvMode = TextureEnvMode.Modulate; switch (matgroup.m_PolyAttribs & 0xC0) { case 0x00: matgroup.m_CullMode = CullFaceMode.FrontAndBack; break; case 0x40: matgroup.m_CullMode = CullFaceMode.Front; break; case 0x80: matgroup.m_CullMode = CullFaceMode.Back; break; } matgroup.m_DiffuseColor = Helper.BGR15ToColor((ushort)matgroup.m_DifAmbColors); matgroup.m_AmbientColor = Helper.BGR15ToColor((ushort)(matgroup.m_DifAmbColors >> 16)); matgroup.m_SpecularColor = Helper.BGR15ToColor((ushort)matgroup.m_SpeEmiColors); matgroup.m_EmissionColor = Helper.BGR15ToColor((ushort)(matgroup.m_SpeEmiColors >> 16)); switch (matgroup.m_TexParams >> 30) { case 0: matgroup.m_TexCoordScale = new Vector2(1.0f, 1.0f); matgroup.m_TexCoordTrans = new Vector2(0.0f, 0.0f); break; case 1: { int sscale = (int)m_File.Read32(mchunkoffset + 0x0C); int tscale = (int)m_File.Read32(mchunkoffset + 0x10); int strans = (int)m_File.Read32(mchunkoffset + 0x18); int ttrans = (int)m_File.Read32(mchunkoffset + 0x1C); matgroup.m_TexCoordScale = new Vector2((float)sscale / 4096.0f, (float)tscale / 4096.0f); matgroup.m_TexCoordTrans = new Vector2((float)strans / 4096.0f, (float)ttrans / 4096.0f); //matgroup.m_TexCoordTrans = new Vector2(0.0f, 16.0f); /*System.Windows.Forms.MessageBox.Show(String.Format("textransform: scale:{0} trans:{1} rot:{2:X8}", matgroup.m_TexCoordScale, matgroup.m_TexCoordTrans, m_File.Read32(mchunkoffset + 0x1C)));*/ } break; case 2: goto case 1; case 3: goto case 1; default: break; // throw new Exception(String.Format("BMD: unsupported texture coord transform mode {0}", matgroup.m_TexParams >> 30)); } if (texid != 0xFFFFFFFF) { matgroup.m_Texture = ReadTexture(texid, palid); matgroup.m_TexParams |= matgroup.m_Texture.m_Params; } else matgroup.m_Texture = null; uint pchunkoffset = m_File.Read32((uint)(m_PolyChunksOffset + (polyID * 8) + 4)); uint dloffset = m_File.Read32(pchunkoffset + 0x0C); uint dlsize = m_File.Read32(pchunkoffset + 0x08); uint numbones = m_File.Read32(pchunkoffset); uint bonesoffset = m_File.Read32(pchunkoffset + 0x04); matgroup.m_BoneIDs = new ushort[numbones]; for (uint b = 0; b < numbones; b++) { byte idx1 = m_File.Read8(bonesoffset + b); matgroup.m_BoneIDs[b] = m_File.Read16((uint)(m_BoneMapOffset + (2 * idx1))); } matgroup.m_Geometry = new List<VertexList>(); m_CurVertex.m_Position = new Vector3(0, 0, 0); m_CurVertex.m_TexCoord = new Vector2(0, 0); if ((matgroup.m_DifAmbColors & 0x8000) == 0x8000) { byte alpha = (byte)((matgroup.m_PolyAttribs >> 13) & 0xF8); alpha |= (byte)(alpha >> 5); matgroup.m_Alpha = alpha; m_CurVertex.m_Color = Color.FromArgb(alpha, matgroup.m_DiffuseColor); } else m_CurVertex.m_Color = Color.Black; m_CurVertex.m_MatrixID = 0; uint dlend = dloffset + dlsize; for (uint pos = dloffset; pos < dlend; ) { byte cmd1 = m_File.Read8(pos++); byte cmd2 = m_File.Read8(pos++); byte cmd3 = m_File.Read8(pos++); byte cmd4 = m_File.Read8(pos++); ProcessGXCommand(matgroup, cmd1, ref pos); ProcessGXCommand(matgroup, cmd2, ref pos); ProcessGXCommand(matgroup, cmd3, ref pos); ProcessGXCommand(matgroup, cmd4, ref pos); } } } foreach (ModelChunk mdchunk in m_ModelChunks) { foreach (MaterialGroup matgroup in mdchunk.m_MatGroups) { matgroup.m_BoneMatrices = new Matrix4[matgroup.m_BoneIDs.Length]; for (uint b = 0; b < matgroup.m_BoneIDs.Length; b++) matgroup.m_BoneMatrices[b] = m_ModelChunks[matgroup.m_BoneIDs[b]].m_Transform; } } }
public void ReadStrings(String fileName) { file = Program.m_ROM.GetFileFromName(fileName); inf1size = file.Read32(0x24); ushort numentries = file.Read16(0x28); m_MsgData = new string[numentries]; m_StringLengths = new int[numentries]; m_ShortVersions = new string[numentries]; m_FileSize = file.Read32(0x08); m_StringHeaderAddr = new uint[numentries]; m_StringHeaderData = new uint[numentries]; m_DAT1Start = 0x20 + inf1size + 0x08; for (int i = 0; i < numentries; i++) { m_StringHeaderAddr[i] = (uint)(0x20 + 0x10 + (i * 8)); m_StringHeaderData[i] = file.Read32(m_StringHeaderAddr[i]); } lbxMsgList.Items.Clear(); //Reset list of messages lbxMsgList.BeginUpdate(); // Only draw when EndUpdate is called, much faster, expecially for Mono for (int i = 0; i < m_MsgData.Length; i++) { uint straddr = file.Read32((uint)(0x30 + i * 8)); straddr += 0x20 + inf1size + 0x8; int length = 0; string thetext = ""; for (; ;) { byte cur; try { cur = file.Read8(straddr); } catch { break; } straddr++; length++; char thechar = '\0'; /*if ((cur >= 0x00) && (cur <= 0x09)) * thechar = (char)('0' + cur); * else if ((cur >= 0x0A) && (cur <= 0x23)) * thechar = (char)('A' + cur - 0x0A); * else if ((cur >= 0x2D) && (cur <= 0x46)) * thechar = (char)('a' + cur - 0x2D); * else if ((cur >= 0x50) && (cur <= 0xCF))//Extended ASCII Characters * thechar = (char)(0x30 + cur);*/ // Some characters are two bytes long, can skip the second if (langNames[langIndex] == "jpn") { if (JAP_CHARS.GetFirstToSecond().ContainsKey(cur)) { thetext += JAP_CHARS.GetByFirst(cur); straddr += (JAP_SIZES[JAP_CHARS.GetByFirst(cur)] - 1); length += (int)(JAP_SIZES[JAP_CHARS.GetByFirst(cur)] - 1); } } else { if ((cur >= 0x00 && cur <= 0x4F) || (cur >= 0xEE && cur <= 0xFB)) { thetext += BASIC_EUR_US_CHARS.GetByFirst(cur); straddr += (BASIC_EUR_US_SIZES[BASIC_EUR_US_CHARS.GetByFirst(cur)] - 1); length += (int)(BASIC_EUR_US_SIZES[BASIC_EUR_US_CHARS.GetByFirst(cur)] - 1); } else if (cur >= 0x50 && cur <= 0xCF) { thetext += EXTENDED_ASCII_CHARS.GetByFirst(cur); straddr += (EXTENDED_ASCII_SIZES[EXTENDED_ASCII_CHARS.GetByFirst(cur)] - 1); length += (int)(EXTENDED_ASCII_SIZES[EXTENDED_ASCII_CHARS.GetByFirst(cur)] - 1); } } if (thechar != '\0') { thetext += thechar; } else if (cur == 0xFD) { thetext += "\r\n"; } else if (cur == 0xFF) { break; } else if (cur == 0xFE)// Special Character { int len = file.Read8(straddr); thetext += "[\\r]"; thetext += String.Format("{0:X2}", cur); for (int spec = 0; spec < len - 1; spec++) { thetext += String.Format("{0:X2}", file.Read8((uint)(straddr + spec))); } length += (len - 1);// Already increased by 1 at start straddr += (uint)(len - 1); } } m_MsgData[i] = thetext; m_StringLengths[i] = length; m_ShortVersions[i] = ShortVersion(m_MsgData[i], i); lbxMsgList.Items.Add(m_ShortVersions[i]); btnImport.Enabled = true; btnExport.Enabled = true; } lbxMsgList.EndUpdate(); }
private void loadExternalToolStripMenuItem_Click(object sender, EventArgs e) { int texDefID = lbxTexDef.SelectedIndex; // this shouldn't happen but you never know if (texDefID == -1) { return; } m_ROMFileSelect.ReInitialize("Select a SPT file to load", new String[] { ".spt" }); DialogResult result = m_ROMFileSelect.ShowDialog(); if (result != DialogResult.OK) { return; } else { try { NitroFile SPT = Program.m_ROM.GetFileFromName(m_ROMFileSelect.m_SelectedFile); if (SPT.Read32(0x0) != 0x53505420) { throw new Exception("Invalid SPT header."); } uint flags = SPT.Read32(0x04); uint texelArrSize = SPT.Read32(0x08); uint palOffset = SPT.Read32(0x0c); uint palSize = SPT.Read32(0x10); uint totalSize = SPT.Read32(0x1c); byte[] texels = SPT.ReadBlock(0x20, texelArrSize); byte[] palette = SPT.ReadBlock(palOffset, palSize); int width = 1 << (((int)flags >> 4 & 0xf) + 3); int height = 1 << (((int)flags >> 8 & 0xf) + 3); bool color0Transp = ((flags & 0x8) | (flags & 0x10000)) != 0; int type = (int)flags & 0x7; Particle.Texture.RepeatMode repeatX = (flags & 0x4000) != 0 ? Particle.Texture.RepeatMode.FLIP : (flags & 0x1000) != 0 ? Particle.Texture.RepeatMode.REPEAT : Particle.Texture.RepeatMode.CLAMP; Particle.Texture.RepeatMode repeatY = (flags & 0x8000) != 0 ? Particle.Texture.RepeatMode.FLIP : (flags & 0x2000) != 0 ? Particle.Texture.RepeatMode.REPEAT : Particle.Texture.RepeatMode.CLAMP; m_TexDefs[texDefID].Unload(); m_TexDefs[texDefID] = new Particle.Texture(texels, palette, width, height, (byte)(color0Transp ? 1 : 0), type, repeatX, repeatY, texDefID); m_TexDefs[texDefID].Load(); UpdateParticleTextures(texDefID); } catch (Exception ex) { MessageBox.Show("Failed to load external SPT. Details:\n" + ex.Message, "Failed to load SPT"); } RefreshImage(); PopulatePaletteSettings(); } }