public Bitmap LoadImage(Boolean usingTMap, int sizeX, int sizeY, int bpp, int paletteRow = 0) { Bitmap bmp = new Bitmap(sizeX, sizeY); uint tileoffset = 0, tilenum = 0; ushort tilecrap = 0; for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { if (usingTMap) { tilecrap = m_TileMapFile.Read16(tileoffset); tilenum = (uint)(tilecrap & 0x03FF); } 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); //Address of current pixel byte palentry = m_TileSetFile.Read8(totaloffset); //Offset of current pixel's entry in palette file //Palentry is double to get the position of the colour in the palette file ushort pixel = m_PalFile.Read16((uint)(palentry * 2)); //Colour of current pixel from palette file bmp.SetPixel(mx + tx, my + ty, Helper.BGR15ToColor(pixel)); } else if (bpp == 4) { float totaloffset = (float)((float)(tilenum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = 0; if (totaloffset % 1 == 0) { palentry = m_TileSetFile.Read8((uint)totaloffset); //Offset of current pixel's entry in palette file palentry = (byte)(palentry & 0x0F); // Get 4 right bits } else { palentry = m_TileSetFile.Read8((uint)totaloffset); //Offset of current pixel's entry in palette file palentry = (byte)(palentry >> 4); // Get 4 left bits } //Palentry is double to get the position of the colour in the palette file ushort pixel = m_PalFile.Read16((uint)((palentry * 2) + (m_PaletteRow * 32)));//Colour of current pixel from palette file bmp.SetPixel(mx + tx, my + ty, Helper.BGR15ToColor(pixel)); } } } tileoffset += 2; if (!usingTMap) { tilenum++; } } } return(bmp); }
/* 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 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); }
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 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 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 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 AnimationDescriptor(NitroFile file, uint offset) { m_Interpolate = file.Read8(offset + 0x00); m_ConstantValue = (file.Read8(offset + 0x01) != 1); m_StartOffset = file.Read16(offset + 0x02); }
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 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 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 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++; } }
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 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 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\nYou must import an indexed bitmap with a maximum of 256 colours."); 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]))); } // Pad the palette to a multiple of 16 colours byte nColourSlots = (byte)((palette.Length % 16 != 0) ? ((palette.Length + 16) & ~15) : palette.Length); for (int i = palette.Length; i < nColourSlots; 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 since minimap sizes are hard-coded, // they are not based on the size of the imported image. 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); } } m_SizeX = sizeX; m_SizeY = sizeY; }