private void chooseTileset_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Title = "Select file"; openFileDialog1.CheckFileExists = true; openFileDialog1.CheckPathExists = true; openFileDialog1.Filter = "1PP tileset binary (*.tsb)|*.tsb"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { activeTsb = new tsbfile(); activeTsb.form1 = form1; activeTsb.filepath = openFileDialog1.FileName; activeTsb.filebytes = File.ReadAllBytes(activeTsb.filepath); activeTsb.Load(); } }
private void importFromPNG_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Title = "Select image file"; openFileDialog1.CheckFileExists = true; openFileDialog1.CheckPathExists = true; openFileDialog1.Filter = "PNG image (*.png)|*.png"; if (openFileDialog1.ShowDialog() == DialogResult.OK) { activeTsb = new tsbfile(); activeMpb = new mpbfile(); activeMpb.editorForm = this; Bitmap image = (Bitmap)Image.FromFile(openFileDialog1.FileName); //check dimensions if (image.Width % 8 != 0) { MessageBox.Show("Image width must be a multiple of 8.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } if (image.Height % 8 != 0) { MessageBox.Show("Image height must be a multiple of 8.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } //check palette List <Color> palette = new List <Color>(); for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { Color newColour = image.GetPixel(x, y); if (!palette.Contains(newColour)) { palette.Add(newColour); } if (palette.Count > 256) { MessageBox.Show("The image must not have more than 256 colours.", "Too many colours", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } } } if (palette.Count < 256 && !palette.Contains(Color.FromArgb(0xFF, 0xFF, 0x00, 0xFF)) && !palette.Contains(Color.FromArgb(0x00, 0xFF, 0x00, 0xFF))) //if there's space for it, sneakily add the magenta alpha anyway { palette.Add(Color.FromArgb(0xFF, 0xFF, 0x00, 0xFF)); } TSBAlphaColour = Color.FromArgb(0xFF, 0xFF, 0x00, 0xFF); MessageBox.Show("Alpha colour is enforced as RGB 0xFF00FF (a bright magenta). If you don't have this colour in your image, an unexpected colour may turn transparent in-game!", "Notice", MessageBoxButtons.OK, MessageBoxIcon.Information); //swap the alpha colour to the start for (int c = 0; c < palette.Count; c++) { if ((palette[c].R & 0xF8) == (TSBAlphaColour.R & 0xF8) && (palette[c].G & 0xF8) == (TSBAlphaColour.G & 0xF8) && (palette[c].B & 0xF8) == (TSBAlphaColour.B & 0xF8)) { //swap the first slot colour here, and put the alpha colour in the first slot instead palette[c] = palette[0]; palette[0] = TSBAlphaColour; break; } } //truncate colours TSBAlphaColour = Color.FromArgb(0xFF, TSBAlphaColour.R & 0xF8, TSBAlphaColour.G & 0xF8, TSBAlphaColour.B & 0xF8); for (int c = 0; c < palette.Count; c++) { palette[c] = Color.FromArgb(0xFF, palette[c].R & 0xF8, palette[c].G & 0xF8, palette[c].B & 0xF8); } //turn image into tiles activeTsb.palette = palette.ToArray(); byte[] NBFCimage = (form1.ImageToNBFC(image, 8, activeTsb.palette)); NBFCimage.Reverse(); List <Tile> tiles = new List <Tile>(); int width_in_tiles = image.Width / 8; int height_in_tiles = image.Height / 8; int pos = 0; List <Tile> uniqueTiles = new List <Tile>(); for (int y = 0; y < height_in_tiles; y++) { for (int x = 0; x < width_in_tiles; x++) { //make a new tile from the current pos in the image Tile newTile = new Tile(); for (int i = 7; i >= 0; i--) { Array.Copy(NBFCimage, pos + (image.Width * i), newTile.tileImage, 8 * i, 8); } //now that we have the tile, compare it to the other tiles for (int t = 0; t < tiles.Count; t++) { if (tiles[t].hasSimilarTile) //only use tiles that aren't already references to other tiles { continue; } int tileSimilarlity = AreTilesSimilar(newTile, tiles[t]); if (tileSimilarlity > 0) //if they are similar (i.e. identical but one of them is a mirror of the other) { newTile.hasSimilarTile = true; newTile.SimilarTile = tiles[t]; if (tileSimilarlity == 1) //then they are just the same tile { } else if (tileSimilarlity == 2) //then they are the same but one of them is X flipped { newTile.flipX = true; } else if (tileSimilarlity == 3) //then they are the same but one of them is Y flipped { newTile.flipY = true; } else if (tileSimilarlity == 4) //then they are the same but one of them is flipped on both X and Y { newTile.flipX = true; newTile.flipY = true; } break; } } if (!newTile.hasSimilarTile) { uniqueTiles.Add(newTile); } tiles.Add(newTile); pos += 8; } if (pos % image.Width == 0) { pos += image.Width * 7; } } //now we should have a list of tiles, some of which are mirrors of each other if applicable activeTsb.filebytes = new byte[0x200 + (uniqueTiles.Count * 64)]; //now write palette to tsb for (int c = 0; c < palette.Count; c++) { ushort ABGR1555Colour = form1.ColorToABGR1555(palette[c]); activeTsb.filebytes[(c * 2)] = (byte)ABGR1555Colour; activeTsb.filebytes[(c * 2) + 1] = (byte)(ABGR1555Colour >> 8); } //now write tiles to tsb, but only the ones that are their own tile and not just referencing another one int tileWritingPos = 0x200; for (int t = 0; t < uniqueTiles.Count; t++) { if (!uniqueTiles[t].hasSimilarTile) //only process it if it's a master tile { foreach (Byte b in uniqueTiles[t].tileImage) { activeTsb.filebytes[tileWritingPos] = b; tileWritingPos++; } } } //MPB activeMpb.filebytes = new byte[tiles.Count * 2]; for (int t = 0; t < tiles.Count; t++) { ushort tileDescriptor = 0; if (tiles[t].hasSimilarTile) { //then write a reference to the similar tile instead tileDescriptor = (ushort)uniqueTiles.IndexOf(tiles[t].SimilarTile); if (tileDescriptor > 8191) { //if it's 8192 or above, start counting from zero again and set the third bit. Yeah it seems like this is what should happen anyway, but the third bit seemed to be doing weird things before, and this method works. tileDescriptor -= 8192; tileDescriptor |= 0x2000; } if (tiles[t].flipX) { tileDescriptor |= 0x4000; } if (tiles[t].flipY) { tileDescriptor |= 0x8000; } } else //otherwise, just write this tile normally { tileDescriptor = (ushort)uniqueTiles.IndexOf(tiles[t]); } activeMpb.filebytes[(t * 2)] = (byte)tileDescriptor; activeMpb.filebytes[(t * 2) + 1] = (byte)(tileDescriptor >> 8); } LoadBoth(); } }