private void PopulatePaletteSettings() { int texDefID = lbxTexDef.SelectedIndex; if (texDefID == -1 || texDefID >= internalTexs) { grdPalette.ClearColours(); return; } byte[] palette = m_TexDefs[texDefID].m_Tex.m_RawPaletteData; int nColours = palette.Length / 2; Color[] paletteColours = new Color[nColours]; for (int i = 0; i < nColours; i++) { ushort palColour = (ushort)(palette[(i * 2)] | (palette[(i * 2) + 1] << 8)); paletteColours[i] = Helper.BGR15ToColor(palColour); } grdPalette.SetColours(paletteColours); btnModelPalettesSelectedColour.Enabled = true; }
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); }
private void LoadPalette() { gridPalette.RowCount = 16; gridPalette.ColumnCount = 16; //Read palette colours Color[] paletteColours = new Color[256]; for (int i = 0; i < m_PalFile.m_Data.Length / 2; i++) { //Colour in BGR15 format (16 bits) written to every even address 0,2,4... ushort palColour = m_PalFile.Read16((uint)(i * 2)); paletteColours[i] = Helper.BGR15ToColor(palColour); } for (int i = m_PalFile.m_Data.Length / 2; i < 256; i++) { paletteColours[i] = Helper.BGR15ToColor(0);// Fill blank entries with black } //Display palette colours int clr = 0; for (int row = 0; row < gridPalette.RowCount; row++) //For every row { gridPalette.Columns[row].Width = 16; //Set each cell's width to 16 for (int column = 0; column < gridPalette.ColumnCount; column++) //For every column { gridPalette.Rows[row].Cells[column].Style.BackColor = paletteColours[clr]; //Set the cell colour to the corresponding palette colour clr += 1; } } gridPalette.CurrentCell.Selected = false;//Select none by default }
private void LoadPalette() { // Read palette colours Color[] paletteColours = new Color[256]; for (int i = 0; i < m_PalFile.m_Data.Length / 2; i++) { // Colour in BGR15 format (16 bits) written to every even address 0,2,4... ushort palColour = m_PalFile.Read16((uint)(i * 2)); paletteColours[i] = Helper.BGR15ToColor(palColour); } gridPalette.SetColours(paletteColours); }
private void ExportPaletteAsACT(string fileName) { byte[] data = new byte[256 * 3]; int numColours = m_PalFile.m_Data.Length / 2; for (int i = 0; i < numColours; i++) { Color currentColour = Helper.BGR15ToColor(m_PalFile.Read16((uint)(i * 2))); data[(i * 3) + 0] = (byte)currentColour.R; data[(i * 3) + 1] = (byte)currentColour.G; data[(i * 3) + 2] = (byte)currentColour.B; } System.IO.File.WriteAllBytes(fileName, data); }
private void PopulatePaletteSettings() { byte[] palette = m_Texture.m_Tex.m_RawPaletteData; int nColours = palette.Length / 2; Color[] paletteColours = new Color[nColours]; for (int i = 0; i < nColours; i++) { ushort palColour = (ushort)(palette[(i * 2)] | (palette[(i * 2) + 1] << 8)); paletteColours[i] = Helper.BGR15ToColor(palColour); } grdPalette.SetColours(paletteColours); btnModelPalettesSelectedColour.Enabled = true; }
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { ColorDialog dialog = new ColorDialog(); int oldColor = (int)(((Color)value).ToArgb() & ~0xff000000); oldColor = oldColor & 0x0000ff00 | oldColor << 16 & 0x00ff0000 | oldColor >> 16 & 0x000000ff; dialog.CustomColors = new int[] { oldColor }; dialog.Color = (Color)value; if (dialog.ShowDialog() == DialogResult.OK) { Color color = dialog.Color; color = Helper.BGR15ToColor(Helper.ColorToBGR15(color)); return(color); } return(value); }
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; }
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++; } }