public static BMD GetModel(string name) { if (Program.m_ROM == null) { return(null); } if (m_Models.ContainsKey(name)) { CachedModel found = m_Models[name]; found.m_References++; return(found.m_Model); } NitroFile mdfile = Program.m_ROM.GetFileFromName(name); if (mdfile == null) { return(null); } BMD model = new BMD(mdfile); model.PrepareToRender(); CachedModel cmdl = new CachedModel(); cmdl.m_Model = model; cmdl.m_DisplayLists = null; cmdl.m_References = 1; m_Models.Add(name, cmdl); return(model); }
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; } } } } }
private void btnLZDecompressWithHeader_Click(object sender, EventArgs e) { NitroFile file = Program.m_ROM.GetFileFromName(m_SelectedFile); // NitroFile automatically decompresses on load if LZ77 header present file.SaveChanges(); }
public static KCL GetKCL(string name) { if (m_Clsns.ContainsKey(name)) { CachedKCL found = m_Clsns[name]; found.m_References++; return(found.m_Clsn); } if (!Program.m_ROM.FileExists(name)) { return(null); } NitroFile kclfile = Program.m_ROM.GetFileFromName(name); KCL clsn = new KCL(kclfile); CachedKCL ckcl = new CachedKCL(); ckcl.m_Clsn = clsn; ckcl.m_References = 1; m_Clsns.Add(name, ckcl); return(clsn); }
public SDAT(NitroFile sdat) { m_File = sdat; m_FileName = m_File.m_Name; m_Header = new SDATHeader(m_File); m_Info = new SDATInfo(m_File, m_Header.m_InfoOffset); }
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 BCA(NitroFile file) { m_File = file; m_FileName = m_File.m_Name; ReadHeader(); ReadAnimationData(); }
private void btnKCLEditor_Click(object sender, EventArgs e) { uint ovlID = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex); NitroOverlay curOvl = new NitroOverlay(Program.m_ROM, ovlID); NitroFile curKCL = Program.m_ROM.GetFileFromInternalID(curOvl.Read16((uint)(0x6A))); KCLEditorForm kclForm = new KCLEditorForm(curKCL); kclForm.Show(); }
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 KCLEditorForm(NitroFile kclIn) { InitializeComponent(); LoadKCL(kclIn); LoadColours(); cmbPolygonMode.Items.Add("Fill"); cmbPolygonMode.Items.Add("Wireframe"); cmbPolygonMode.SelectedIndex = 0; matColTypes = new Dictionary <string, int>(); }
public KCLEditorForm(NitroFile kclIn) { InitializeComponent(); LoadKCL(kclIn); LoadColours(); cmbPolygonMode.Items.Add("Fill"); cmbPolygonMode.Items.Add("Wireframe"); cmbPolygonMode.SelectedIndex = 0; matColTypes = new Dictionary<string, int>(); }
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 BMD_KLC_Editor(string fileName) { InitializeComponent(); panProperties.Controls.Clear(); m_ModelName = fileName; if (m_ModelName.EndsWith(".bmd")) { m_ModelFile = Program.m_ROM.GetFileFromName(m_ModelName); m_Model = new BMD(m_ModelFile); Text = fileName.Split('/').Last(); TreeNode modelNode = tvModelContent.Nodes.Add("Model"); TreeNode chunksNode = modelNode.Nodes.Add("Chunks"); int i = 0; foreach (BMD.ModelChunk chunk in m_Model.m_ModelChunks) { TreeNode chunkNode = chunksNode.Nodes.Add(i.ToString(), chunk.m_Name); chunkNode.Tag = chunk; TreeNode matGroupsNode = chunkNode.Nodes.Add("Material Groups"); int i2 = 0; foreach (BMD.MaterialGroup matGroup in chunk.m_MatGroups) { TreeNode matGroupNode = matGroupsNode.Nodes.Add(i2.ToString(), matGroup.m_Name); matGroupNode.Tag = matGroup; TreeNode vtxListsNode = matGroupNode.Nodes.Add("Vertex Lists"); int i3 = 0; foreach (BMD.VertexList vtxList in matGroup.m_Geometry) { TreeNode vtxListNode = vtxListsNode.Nodes.Add(i3.ToString(), "Vertex Group[" + i3.ToString() + "] (" + m_primitiveNames[vtxList.m_PolyType] + ")"); vtxListNode.Tag = vtxList; TreeNode vertsNode = vtxListNode.Nodes.Add("Vertices"); int i4 = 0; foreach (BMD.Vertex vtx in vtxList.m_VertexList) { TreeNode vtxNode = vertsNode.Nodes.Add(i4.ToString(), "Vertex[" + i4.ToString() + "] (" + vtx.m_Position + ")"); vtxNode.Tag = vtx; vtxNode.Nodes.Add("Position: " + vtx.m_Position); vtxNode.Nodes.Add("Normal: " + vtx.m_Normal); vtxNode.Nodes.Add("Texture Coordinates: " + vtx.m_TexCoord); vtxNode.Nodes.Add("Vertex Color: " + vtx.m_Color); vtxNode.Nodes.Add("Matrix ID: " + vtx.m_MatrixID); i4++; } i3++; } i2++; } i++; } } }
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 void LoadKCL(NitroFile kcl) { m_KCL = new KCL(kcl); m_Planes = m_KCL.m_Planes; lbxPlanes.Items.Clear(); for (int i = 0; i < m_Planes.Count; i++) { lbxPlanes.Items.Add("Plane " + i.ToString("00000")); } }
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)); } }
public KCLEditorForm(NitroFile kclIn) { InitializeComponent(); LoadKCL(kclIn); cmbPolygonMode.Items.Add("Fill"); cmbPolygonMode.Items.Add("Wireframe"); cmbPolygonMode.SelectedIndex = 0; glModelView.Initialise(); glModelView.ProvidePickingDisplayLists(m_KCLMeshPickingDLists); glModelView.ProvideDisplayLists(m_KCLMeshDLists); glModelView.ProvideCallListForDisplayLists(CallListForKCLDisplayLists); }
private void LoadMinimapFiles() { m_PalFile = Program.m_ROM.GetFileFromInternalID(m_Level.m_LevelSettings.MinimapPalFileID); m_TileSetFile = Program.m_ROM.GetFileFromInternalID(m_Level.m_LevelSettings.MinimapTsetFileID); for (int j = 0; j < m_NumAreas; j++) { try { if (j < m_Level.m_MinimapFileIDs.Length && m_Level.m_MinimapFileIDs[j] != 0) { m_TileMapFiles[j] = (Program.m_ROM.GetFileFromInternalID(m_Level.m_MinimapFileIDs[j])); tsMinimapEditor.Items[1 + j].Enabled = true; } else { tsMinimapEditor.Items[1 + j].Enabled = false; } } catch//If the file doesn't exist { tsMinimapEditor.Items[1 + j].Enabled = false; } } m_TileMapFile = m_TileMapFiles[m_CurArea]; m_TileMapFile.ForceDecompression();// Only to get accurate size below m_IsUsingTileMap = true; m_SizeX = m_SizeY = (int)(Math.Sqrt(m_TileMapFile.m_Data.Length / 2) * 8); // Minimaps are squares m_BPP = 8; // Bits per pixel is always 8 for the minimaps dmnHeight.Text = dmnWidth.Text = "" + m_SizeX; m_PaletteRow = 0; dmnPaletteRow.Text = "" + m_PaletteRow; cbxBPP.SelectedIndex = 1; if (m_SizeX == 128) { chk128.Checked = true; chk256.Checked = false; } else if (m_SizeX == 256) { chk128.Checked = false; chk256.Checked = true; } txtSelNCG.Text = m_TileSetFile.m_Name; txtSelNCL.Text = m_PalFile.m_Name; txtSelNSC.Text = m_TileMapFile.m_Name; }
private void LoadBTP(String filename) { try { NitroFile file = Program.m_ROM.GetFileFromName(filename); m_BTP = new BTP(file); LoadOnlyBTPReferencedTextures(); PopulateBTPListBoxes(); EnableBTPFormControls(); } catch (Exception ex) { MessageBox.Show("Error loading BTP:\n" + ex.Message + "\n" + ex.StackTrace); } }
public void LoadKCL(NitroFile kcl) { m_KCL = new KCL(kcl); m_Planes = m_KCL.m_Planes; lbxPlanes.Items.Clear(); for (int i = 0; i < m_Planes.Count; i++) { lbxPlanes.Items.Add("Plane " + i.ToString("00000")); } LoadColours(); }
private void btnLZForceCompression_Click(object sender, EventArgs e) { NitroFile file = Program.m_ROM.GetFileFromName(m_SelectedFile); try { file.ForceCompression(); } catch (Exception ex) { MessageBox.Show("There was an error trying to compress the file \"" + file.m_Name + "\" with " + "LZ77 compression (no header)\n\n" + ex.Message + "\n\n" + ex.StackTrace); } file.SaveChanges(); }
public SDATInfoPLAYER2(NitroFile sdat, uint offset) { m_Offset = offset; m_Count = sdat.Read8(m_Offset + 0x00); m_ChannelNumber = new byte[16]; for (int i = 0; i < 16; i++) { m_ChannelNumber[i] = sdat.Read8(m_Offset + 0x01 + (uint)(i)); } m_Padding = new byte[7]; for (int i = 0; i < 7; i++) { m_Padding[i] = sdat.Read8(m_Offset + 0x11 + (uint)(i)); } }
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 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); }
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(); }
/// <summary> /// Open KPS. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void openToolStripMenuItem_Click(object sender, EventArgs e) { ROMFileSelect r = new ROMFileSelect(); r.ShowDialog(); string file = r.m_SelectedFile; if (file != null && file != "") { nf = new NitroFile(Program.m_ROM, Program.m_ROM.GetFileIDFromName(file)); MemoryStream src = new MemoryStream(nf.m_Data); BinaryReader br = new BinaryReader(src); if (src.Length >= 0x10) { UInt32 magic1 = br.ReadUInt32(); UInt32 magic2 = br.ReadUInt32(); if (magic1 == 0x00100001) { if (magic2 == 0x00140018) { OpenDkl(nf.m_Data, false); } else if (magic2 == 0x0018001C) { OpenDkl(nf.m_Data, true); } else { OpenBin(nf.m_Data); } } else { OpenBin(nf.m_Data); } } else { OpenBin(nf.m_Data); } } }
private void btnEditCollisionMap_Click(object sender, EventArgs e) { uint overlayID = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex); NitroOverlay currentOverlay = new NitroOverlay(Program.m_ROM, overlayID); NitroFile currentKCL = Program.m_ROM.GetFileFromInternalID(currentOverlay.Read16((uint)(0x6A))); if (!Properties.Settings.Default.UseSimpleModelAndCollisionMapImporters) { ModelAndCollisionMapEditor kclForm = new ModelAndCollisionMapEditor(null, currentKCL.m_Name, 1f, ModelAndCollisionMapEditor.StartMode.CollisionMap); kclForm.Show(); } else { KCLEditorForm kclForm = new KCLEditorForm(currentKCL); kclForm.Show(); } }
private void TextureEditorForm_Load(object sender, System.EventArgs e) { if (m_Name == null) { m_ROMFileSelect.ReInitialize("Select a SPT file to load", new string[] { ".spt" }); DialogResult result = m_ROMFileSelect.ShowDialog(); if (result != DialogResult.OK) { Close(); } else { m_Name = m_ROMFileSelect.m_SelectedFile; m_ParticleTexFile = Program.m_ROM.GetFileFromName(m_Name); cmbRepeatX.Items.Add(Particle.Texture.RepeatMode.CLAMP); cmbRepeatX.Items.Add(Particle.Texture.RepeatMode.REPEAT); cmbRepeatX.Items.Add(Particle.Texture.RepeatMode.FLIP); cmbRepeatX.SelectedIndex = -1; cmbRepeatY.Items.Add(Particle.Texture.RepeatMode.CLAMP); cmbRepeatY.Items.Add(Particle.Texture.RepeatMode.REPEAT); cmbRepeatY.Items.Add(Particle.Texture.RepeatMode.FLIP); cmbRepeatY.SelectedIndex = -1; cmbFormat.Items.Add("A3I5"); cmbFormat.Items.Add("Color4"); cmbFormat.Items.Add("Color16"); cmbFormat.Items.Add("Color256"); cmbFormat.Items.Add("Texel4x4 (unsupported)"); cmbFormat.Items.Add("A5I3"); cmbFormat.Items.Add("Direct"); cmbFormat.SelectedIndex = prevFormat = -1; LoadTexture(); RefreshImage(); PopulatePaletteSettings(); UpdateForm(); ResetColourButtonValue(btnModelPalettesSelectedColour); } } }
private void btnReplaceRaw_Click(object sender, EventArgs e) { if (m_SelectedFile == null || m_SelectedFile.Equals("")) { return; } OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.Cancel) { return; } NitroFile file = Program.m_ROM.GetFileFromName(m_SelectedFile); file.Clear(); file.WriteBlock(0, System.IO.File.ReadAllBytes(ofd.FileName)); file.SaveChanges(); }
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 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 SDATInfoPLAYER2(NitroFile sdat, uint offset) { m_Offset = offset; m_Count = sdat.Read8(m_Offset + 0x00); m_ChannelNumber = new byte[16]; for (int i = 0; i < 16; i++) m_ChannelNumber[i] = sdat.Read8(m_Offset + 0x01 + (uint)(i)); m_Padding = new byte[7]; for (int i = 0; i < 7; i++) m_Padding[i] = sdat.Read8(m_Offset + 0x11 + (uint)(i)); }
public void ImportBMP(string filename, int bpp, int sizeX, int sizeY, bool replaceMinimap = false, int numTilesX = 0, int numTilesY = 0, byte[] tilePaletteRows = null) { // The tile maps (NSC / ISC) files for minimaps are always arranged a particular way - 0, 1, 2...15, 32 for 128 x 128 Bitmap bmp = new Bitmap(filename); Color[] palette = bmp.Palette.Entries.ToArray<Color>(); if (palette.Length > 256) { MessageBox.Show("Too many colours\n\n" + "You must import an indexed bitmap with 256 colours or fewer."); return; } //Write new palette m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); m_PalFile.Clear(); for (int i = 0; i < palette.Length; i++) { //Colour in BGR15 format (16 bits) written to every even address 0,2,4... m_PalFile.Write16((uint)i * 2, (ushort)(Helper.ColorToBGR15(palette[i]))); } for (int i = palette.Length; i < 256; i++) m_PalFile.Write16((uint)i * 2, 0); m_PalFile.SaveChanges(); // Fill current tmapfiles to use full mapsize x mapsize if (m_IsUsingTileMap) { m_TileMapFile = Program.m_ROM.GetFileFromName(txtSelNSC.Text); m_TileMapFile.Clear(); sizeX = bmp.Width; sizeY = bmp.Height; uint addr = 0; int curTile = 0; int row = (int)(sizeX / 8); for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { m_TileMapFile.Write16(addr, (ushort)curTile); curTile++; addr += 2; } } if (chkNSCDcmp.Checked) m_TileMapFile.ForceCompression(); m_TileMapFile.SaveChanges(); }// End If usingTMap //Check to see if there's already an identical tile and if so, change the current value to that //Works, but not if you want to keep existing data eg. multiple maps //List<List<byte>> tiles = new List<List<byte>>(); //List<byte> curTilePal = new List<byte>(); //uint tileoffset = 0; //for (int my = 0; my < sizeY; my += 8) //{ // for (int mx = 0; mx < sizeX; mx += 8) // { // ushort tilecrap = tmapfile.Read16(tileoffset); // uint tilenum = (uint)(tilecrap & 0x03FF); // curTilePal = new List<byte>(); // for (int ty = 0; ty < 8; ty++) // { // for (int tx = 0; tx < 8; tx++) // { // uint totaloffset = (uint)(tilenum * 64 + ty * 8 + tx);//Position of current pixel's entry // curTilePal.Add((byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty)))); // } // } // tiles.Add(curTilePal); // if (posInList(tiles, curTilePal) != -1) // { // tmapfile.Write16(tileoffset, (ushort)(posInList(tiles, curTilePal))); // } // tileoffset += 2; // } //} //Write the new image to file m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); m_TileSetFile.Clear(); uint tileoffset = 0; uint tileNum = 0; for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { for (int ty = 0; ty < 8; ty++) { for (int tx = 0; tx < 8; tx++) { if (bpp == 8) { uint totaloffset = (uint)(tileNum * 64 + ty * 8 + tx);//Position of current pixel's entry byte palentry = (byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty))); m_TileSetFile.Write8(totaloffset, (byte)(palentry)); } else if (bpp == 4) { float totaloffset = (float)((float)(tileNum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = (byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty))); int currentTileIndex = (int)tileNum; byte currentTileRowIndex = tilePaletteRows[currentTileIndex]; byte rowStartColourOffset = (byte)(16 * currentTileRowIndex); byte rowEndColourOffset = (byte)(16 * (currentTileRowIndex + 1) - 1); if (palentry < rowStartColourOffset || palentry > rowEndColourOffset) // Referencing colour outisde its row { Color referencedColour = Helper.BGR15ToColor(m_PalFile.Read16((uint)(palentry * 2))); // Find the same colour in the correct row and set the current pixel to reference that instead for (int col = rowStartColourOffset; col < rowEndColourOffset; col++) { uint offset = (uint)(col * 2); if (offset >= m_PalFile.m_Data.Length) break; Color currentColour = Helper.BGR15ToColor(m_PalFile.Read16(offset)); if (currentColour.Equals(referencedColour)) { palentry = (byte)col; break; } } } if (totaloffset % 1 == 0) { // Right 4 bits m_TileSetFile.Write8((uint)totaloffset, (byte)palentry); //(byte)((tsetfile.Read8((uint)totaloffset) & 0xF0) | palentry)); } else { // Left 4 bits m_TileSetFile.Write8((uint)totaloffset, (byte)((palentry << 4) | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F))); } } } } tileoffset += 2; tileNum++; } } if (chkNCGDcmp.Checked) m_TileSetFile.ForceCompression(); m_TileSetFile.SaveChanges(); // If it's a minimap that's being replaced, fill the tile maps to allow for multiple maps // and ensure the image's displayed at the right size as you can't change the size of // a level's minimap - it seems to be hardcoded somewhere (in level header?) if (replaceMinimap) { try { if (chk128.Checked) FillMinimapTiles(128); else if (chk256.Checked) FillMinimapTiles(256); } catch (Exception ex) { MessageBox.Show(ex.Message + ex.Source + ex.StackTrace); } } }
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 LoadMinimapFiles() { m_PalFile = Program.m_ROM.GetFileFromInternalID(_owner.m_LevelSettings.MinimapPalFileID); m_TileSetFile = Program.m_ROM.GetFileFromInternalID(_owner.m_LevelSettings.MinimapTsetFileID); for (int j = 0; j < m_NumAreas; j++) { try { if (j < _owner.m_MinimapFileIDs.Length && _owner.m_MinimapFileIDs[j] != 0) { m_TileMapFiles[j] = (Program.m_ROM.GetFileFromInternalID(_owner.m_MinimapFileIDs[j])); tsMinimapEditor.Items[1 + j].Enabled = true; } else tsMinimapEditor.Items[1 + j].Enabled = false; } catch//If the file doesn't exist { tsMinimapEditor.Items[1 + j].Enabled = false; } } m_TileMapFile = m_TileMapFiles[m_CurArea]; m_TileMapFile.ForceDecompression();// Only to get accurate size below m_IsUsingTileMap = true; m_SizeX = m_SizeY = (int)(Math.Sqrt(m_TileMapFile.m_Data.Length / 2) * 8);// Minimaps are squares m_BPP = 8;// Bits per pixel is always 8 for the minimaps dmnHeight.Text = dmnWidth.Text = "" + m_SizeX; m_PaletteRow = 0; dmnPaletteRow.Text = "" + m_PaletteRow; cbxBPP.SelectedIndex = 1; if (m_SizeX == 128) { chk128.Checked = true; chk256.Checked = false; } else if (m_SizeX == 256) { chk128.Checked = false; chk256.Checked = true; } txtSelNCG.Text = m_TileSetFile.m_Name; txtSelNCL.Text = m_PalFile.m_Name; txtSelNSC.Text = m_TileMapFile.m_Name; }
private void RedrawMinimap(Boolean usingTmap, int sizeX, int sizeY, int bpp, int paletteRow = 0) { m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); if (chkNCGDcmp.Checked) { m_TileSetFile.ForceDecompression(); } m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); dmnPaletteRow.Items.Clear(); for (int i = m_PalFile.m_Data.Length, j = 0; i > 0; i -= 32, j++) { dmnPaletteRow.Items.Insert(0, j); } if (!txtSelNSC.Text.Equals("")) { m_IsUsingTileMap = true; m_TileMapFile = Program.m_ROM.GetFileFromName(txtSelNSC.Text); if (chkNSCDcmp.Checked) { m_TileMapFile.ForceDecompression(); } } else { m_IsUsingTileMap = false; } Bitmap bmp = LoadImage(m_IsUsingTileMap, sizeX, sizeY, bpp, paletteRow); pbxMinimapGfx.Image = new Bitmap(bmp, new Size(sizeX * m_Zoom, sizeY * m_Zoom)); pbxMinimapGfx.Refresh(); LoadPalette(); }
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 void SwitchBackground(int swapped) { m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); //The background colour is the first colour stored in the palette ushort first = m_PalFile.Read16((uint)0);//Read the first colour in the palette file ushort swappedColour = m_PalFile.Read16((uint)(swapped * 2));//Read the colour to be swapped //Colour in BGR15 format (16 bits) written to every even address 0,2,4... m_PalFile.Write16((uint)0, swappedColour);//Write new background colour to first entry m_PalFile.Write16((uint)(swapped * 2), first);//Write the previously first colour to the colour being swapped m_PalFile.SaveChanges(); //Swap all palette file entries for the swapped colours in the graphic file m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); if (chkNCGDcmp.Checked) m_TileSetFile.ForceDecompression(); uint tileoffset = 0, tilenum = 0; ushort tilecrap = 0; for (int my = 0; my < m_SizeY; my += 8) { for (int mx = 0; mx < m_SizeX; mx += 8) { if (m_IsUsingTileMap) { tilecrap = m_TileMapFile.Read16(tileoffset); tilenum = (uint)(tilecrap & 0x03FF); } for (int ty = 0; ty < 8; ty++) { for (int tx = 0; tx < 8; tx++) { if (m_BPP == 8) { uint totaloffset = (uint)(tilenum * 64 + ty * 8 + tx);//Position of current pixel's entry byte palentry = m_TileSetFile.Read8(totaloffset); if (palentry == 0)//If the current pixel points to first colour in palette, m_TileSetFile.Write8(totaloffset, (byte)(swapped));//point it to the swapped colour if (palentry == (byte)swapped)//If the current pixel points to the swapped colour in palette, m_TileSetFile.Write8(totaloffset, (byte)0);//point it to the first colour } else if (m_BPP == 4) { float totaloffset = (float)((float)(tilenum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = 0; if (totaloffset % 1 == 0) { // Right 4 bits palentry = m_TileSetFile.Read8((uint)totaloffset);//Offset of current pixel's entry in palette file palentry = (byte)(palentry & 0x0F);// Get 4 right bits if (palentry == 0)//If the current pixel points to first colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)((m_TileSetFile.Read8((uint)totaloffset) & 0xF0) | swapped));//point it to the swapped colour if (palentry == (byte)swapped)//If the current pixel points to the swapped colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)((m_TileSetFile.Read8((uint)totaloffset) & 0xF0) | 0));//point it to the first colour } else { // Left 4 bits palentry = m_TileSetFile.Read8((uint)totaloffset);//Offset of current pixel's entry in palette file palentry = (byte)(palentry >> 4); if (palentry == 0)//If the current pixel points to first colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)((swapped << 4) | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F)));//point it to the swapped colour if (palentry == (byte)swapped)//If the current pixel points to the swapped colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)(0 | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F)));//point it to the first colour } } } } tileoffset += 2; if (!m_IsUsingTileMap) tilenum++; } } if (chkNCGDcmp.Checked) m_TileSetFile.ForceCompression(); m_TileSetFile.SaveChanges(); RedrawMinimap(m_IsUsingTileMap, m_SizeX, m_SizeY, m_BPP, m_PaletteRow); }
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 SDATInfoSEQARC(NitroFile sdat, uint offset) { m_Offset = offset; m_FileID = sdat.Read32(m_Offset + 0x00); }
public AnimationDescriptor(NitroFile file, uint offset) { m_Interpolate = file.Read8(offset + 0x00); m_ConstantValue = (file.Read8(offset + 0x01) != 1); m_StartOffset = file.Read16(offset + 0x02); }
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 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; } } }