private void btnApply_Click(object sender, EventArgs e) { bool hasChanges = false; for (int i = 0; i < lbBefore.Items.Count; i++) { if (lbBefore.Items[i] != lbAfter.Items[i]) { hasChanges = true; break; } } if (!hasChanges) //Quit out if no changes { this.DialogResult = System.Windows.Forms.DialogResult.Cancel; return; } //if the mode is texture, then do something new. //if the mode is palette, then generate the palette BEFORE making the image if (Mode == SharedMode.Texture) { //IDEA: AVERAGE ALL THE IMAGES TOGETHER, THEN MAKE A CI PALETTE/TEXTURE FROM THAT. THEN WE HAVE OUR TEXTURE. // AFTER THAT, WE NEED TO ASSIGN PALETTES TO IT. I GUESS WE CAN AVERAGE ALL COLORS THAT HIT EACH POINT // FOR EACH IMAGE //Slow process Bitmap refImage = new Bitmap(Images[0].Image); int width = Images[0].Image.Width; int height = Images[0].Height; int pixelCount = width * height; int imageCount = lbAfter.Items.Count; int colorCount = Images[0].ImageReference.BasePalettes[0].Colors.Length; int[] redCount = new int[pixelCount]; int[] blueCount = new int[pixelCount]; int[] greenCount = new int[pixelCount]; int[] alphaCount = new int[pixelCount]; foreach (BitmapWrapper wrapper in lbAfter.Items) { for (int j = 0; j < width; j++) { for (int i = 0; i < height; i++) { Color pixel = wrapper.BMP.GetPixel(i, j); redCount[i + j * wrapper.BMP.Width] += pixel.R; greenCount[i + j * wrapper.BMP.Width] += pixel.G; blueCount[i + j * wrapper.BMP.Width] += pixel.B; alphaCount[i + j * wrapper.BMP.Width] += pixel.A; } } } for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { refImage.SetPixel(i, j, Color.FromArgb(alphaCount[i + j * width] / imageCount, redCount[i + j * width] / imageCount, greenCount[i + j * width] / imageCount, blueCount[i + j * width] / imageCount)); } } //Now do the set-texture palette search method Palette tempPalette = new Palette(-1, new byte[colorCount * 2]); byte[] finalTextureData = TextureConversion.ImageToBinary(Images[0].Format, Images[0].PixelSize, refImage, ref tempPalette, true); Images[0].ImageReference.Texture.RawData = finalTextureData; //Now take this and do some stupid shit for (int k = 0; k < imageCount; k++) { redCount = new int[colorCount]; greenCount = new int[colorCount]; blueCount = new int[colorCount]; alphaCount = new int[colorCount]; Bitmap img = (Bitmap)lbAfter.Items[k]; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { Color color = img.GetPixel(i, j); int textureNum = 0; if (Images[k].PixelSize == Texture.PixelInfo.Size_8b) { textureNum = finalTextureData[i + j * height]; } else { byte val = finalTextureData[(i + j * height) / 2]; if ((i + j * height) % 2 == 0) { textureNum = val >> 4; } else { textureNum = val & 0xF; } } redCount[textureNum] += color.R; greenCount[textureNum] += color.G; blueCount[textureNum] += color.B; alphaCount[textureNum] += color.A; } } //Now that we have the colors added up, we calculate the new colors and that's our new palette! Color[] colors = new Color[colorCount]; for (int i = 0; i < colorCount; i++) { colors[i] = Color.FromArgb(alphaCount[i] / imageCount, redCount[i] / imageCount, greenCount[i] / imageCount, blueCount[i] / imageCount); } byte[] newPaletteData = TextureConversion.PaletteToBinary(colors); Images[k].ImageReference.BasePalettes[0].RawData = newPaletteData; } } else { PaletteMedianCutAnalyzer paletteMaker = new PaletteMedianCutAnalyzer(); foreach (BitmapWrapper wrapper in lbAfter.Items) { for (int i = 0; i < wrapper.BMP.Width; i++) { for (int j = 0; j < wrapper.BMP.Height; j++) { paletteMaker.AddColor(wrapper.BMP.GetPixel(i, j)); } } } Color[] colors = paletteMaker.GetPalette(Images[0].ImageReference.BasePalettes[0].Colors.Length); byte[] paletteData = TextureConversion.PaletteToBinary(colors); Palette palette = new Palette(-1, paletteData); byte[] newPaletteData = palette.RawData; Images[0].ImageReference.BasePalettes[0].RawData = newPaletteData; if (Images[0].PaletteEncoding[0] == MK64Image.MK64ImageEncoding.MIO0) { N64DataElement element; if (!RomProject.Instance.Files[0].HasElementExactlyAt(Images[0].PaletteOffset[0], out element)) { throw new Exception(); } MIO0Block block = (MIO0Block)element; byte[] oldMIO0Data = block.DecodedData; Array.Copy(newPaletteData, 0, oldMIO0Data, Images[0].PaletteBlockOffset[0], newPaletteData.Length); byte[] compressedNewMIO0 = MIO0.Encode(oldMIO0Data); block.RawData = compressedNewMIO0; } //Now generate the images for (int i = 0; i < Images.Count; i++) { MK64Image image = Images[i]; Bitmap bmp = ((BitmapWrapper)lbAfter.Items[i]).BMP; byte[] newData = TextureConversion.ImageToBinary(image.Format, image.PixelSize, bmp, ref palette, false); if (newData == null || newData.Length == 0) { MessageBox.Show("Error: Couldn't convert image file!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } image.ImageReference.Texture.RawData = newData; image.ImageReference.UpdateImage(); if (image.TextureEncoding == MK64Image.MK64ImageEncoding.MIO0) { N64DataElement element; if (!RomProject.Instance.Files[0].HasElementExactlyAt(image.TextureOffset, out element)) { throw new Exception(); } MIO0Block block = (MIO0Block)element; byte[] MIO0Data = block.DecodedData; Array.Copy(newData, 0, MIO0Data, image.TextureBlockOffset, newData.Length); byte[] compressedNewMIO0 = MIO0.Encode(MIO0Data); block.RawData = compressedNewMIO0; } } } }
private void ReplaceMIO0() { //Attempt to load in a new texture and replace. Will not work if the texture size is larger than the one it's replacing if (openFileDialog.ShowDialog() == DialogResult.OK) { Bitmap bmp = (Bitmap)Bitmap.FromFile(openFileDialog.FileName); if (bmp == null) { MessageBox.Show("Error: Couldn't load image file!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (bmp.Height != _image.Height || bmp.Width != _image.Width) { MessageBox.Show("Error: New image must be same size!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } //Think hard about this. If you're compressing the image and/or palette into MIO0, you need to test against that. // Also a form if there's more than one image being affected by this change? Before/afters? //So we need some way to change an F3DEXImage to a new bitmap. but it needs to change texture and palette appropriately, // and most importantly it needs to be able to stop halfway to see how it will affect other images. But if we want to change // the lakitu images, which will change the palette, you'd have to change all of the images at once, right? So how the hell // is this going to work out?? //Also palette editing byte[] newData; byte[] newPaletteData = null; if (_image.Format == Texture.ImageFormat.CI) { Palette palette = new Palette(-1, new byte[(_image.ImageReference.WorkingPalette.Colors.Length * 2) - 200]); newData = TextureConversion.ImageToBinary(_image.Format, _image.PixelSize, bmp, ref palette); newPaletteData = palette.RawData; if (newPaletteData.Length < (_image.ImageReference.WorkingPalette.Colors.Length * 2)) { newPaletteData = Cereal64.Common.Utils.ByteHelper.CombineIntoBytes(newPaletteData, new byte[(_image.ImageReference.WorkingPalette.Colors.Length * 2) - newPaletteData.Length]); } } else { newData = TextureConversion.ImageToBinary(_image.Format, _image.PixelSize, bmp); } if (newData == null || newData.Length == 0) { MessageBox.Show("Error: Couldn't convert image file!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } byte[] oldData = _image.ImageReference.Texture.RawData; byte[] oldPaletteData = null; if (_image.Format == Texture.ImageFormat.CI) { oldPaletteData = _image.ImageReference.BasePalettes[0].RawData; } _image.ImageReference.Texture.RawData = newData; if (_image.Format == Texture.ImageFormat.CI) { _image.ImageReference.BasePalettes[0].RawData = newPaletteData; } _image.ImageReference.UpdateImage(); if (!_image.IsValidImage) { _image.ImageReference.Texture.RawData = oldData; _image.ImageReference.UpdateImage(); MessageBox.Show("Error: Couldn't set image file! File might be too large to load in", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } byte[] oldMIO0RefData = null; N64DataElement el; if (_image.TextureEncoding == MK64Image.MK64ImageEncoding.MIO0) { if (!RomProject.Instance.Files[0].HasElementAt(_image.TextureOffset, out el)) { MessageBox.Show("Error: Couldn't set image file! Could not find MIO0 block.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } MIO0Block block = (MIO0Block)el; byte[] oldMIO0Data = block.DecodedData; oldMIO0RefData = oldMIO0Data; if (_specialMIO0Length == -1 && block.FileOffset == 0x132B50) { _specialMIO0Length = block.RawDataSize; } Array.Copy(newData, 0, oldMIO0Data, _image.TextureBlockOffset, newData.Length); byte[] compressedNewMIO0 = MIO0.Encode(oldMIO0Data); int sizeCompare = (_specialMIO0Length != -1 && block.FileOffset == 0x132B50 ? _specialMIO0Length : block.RawDataSize); if (compressedNewMIO0.Length > sizeCompare) { _image.ImageReference.Texture.RawData = oldData; if (_image.Format == Texture.ImageFormat.CI) { _image.ImageReference.BasePalettes[0].RawData = oldPaletteData; } _image.ImageReference.UpdateImage(); MessageBox.Show("Error: Couldn't set image file! File might be too large to load in", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } block.RawData = compressedNewMIO0; } if (_image.Format == Texture.ImageFormat.CI && _image.PaletteEncoding[0] == MK64Image.MK64ImageEncoding.MIO0) { if (!RomProject.Instance.Files[0].HasElementAt(_image.TextureOffset, out el)) { MessageBox.Show("Error: Couldn't set image file! Could not find MIO0 block.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } MIO0Block block = (MIO0Block)el; byte[] oldMIO0Data = block.DecodedData; Array.Copy(newPaletteData, 0, oldMIO0Data, _image.PaletteBlockOffset[0], newPaletteData.Length); byte[] compressedNewMIO0 = MIO0.Encode(oldMIO0Data); int sizeCompare = (_specialMIO0Length != -1 && block.FileOffset == 0x132B50 ? _specialMIO0Length : block.RawDataSize); if (compressedNewMIO0.Length > sizeCompare) { _image.ImageReference.Texture.RawData = oldData; if (_image.Format == Texture.ImageFormat.CI) { _image.ImageReference.BasePalettes[0].RawData = oldPaletteData; } _image.ImageReference.UpdateImage(); //Revert texture if (_image.TextureEncoding == MK64Image.MK64ImageEncoding.MIO0) { N64DataElement element; if (!RomProject.Instance.Files[0].HasElementExactlyAt(_image.TextureOffset, out element)) { throw new Exception(); } MIO0Block blockText = (MIO0Block)element; blockText.RawData = oldMIO0RefData; } MessageBox.Show("Error: Couldn't set image file! File might be too large to load in", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } block.RawData = compressedNewMIO0; } Image = _image; //Reset it ImageUpdated(); } }
private void btnAddImage_Click(object sender, EventArgs e) { if (_newImageForm == null) { _newImageForm = new NewMK64ImageForm(); } if (_newImageForm.ShowDialog() == DialogResult.OK) { List <MK64Image> newImages = new List <MK64Image>(); foreach (string FileName in _newImageForm.FileNames) { //To do: make it load multiple at a time! Bitmap bmp = (Bitmap)Bitmap.FromFile(FileName); if (bmp == null) { MessageBox.Show("Could not load image:\n" + FileName, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); continue; } byte[] imageData; Texture texture; Palette palette = null; if (_newImageForm.Format == Texture.ImageFormat.CI) { byte[] paletteData = new byte[2 * _newImageForm.PaletteColorCount]; palette = new Palette(-1, paletteData); imageData = TextureConversion.ImageToBinary(_newImageForm.Format, _newImageForm.PixelSize, bmp, ref palette, true); } else { imageData = TextureConversion.ImageToBinary(_newImageForm.Format, _newImageForm.PixelSize, bmp); } texture = new Texture(-1, imageData, _newImageForm.Format, _newImageForm.PixelSize, bmp.Width, bmp.Height); //Now, if necessary, encode the texture!! MIO0Block textureBlock = null, paletteBlock = null; if (_newImageForm.EncodeTexture) { byte[] encodedData = MIO0.Encode(texture.RawData); textureBlock = new MIO0Block(-1, encodedData); textureBlock.AddElement(texture); texture.FileOffset = 0; } if (palette != null && _newImageForm.EncodePalette) { byte[] encodedData = MIO0.Encode(palette.RawData); paletteBlock = new MIO0Block(-1, encodedData); paletteBlock.AddElement(palette); palette.FileOffset = 0; } //Add in the texture/palette to the new data location if (textureBlock != null) { textureBlock.FileOffset = MarioKart64ElementHub.Instance.NewElementOffset; RomProject.Instance.Files[0].AddElement(textureBlock); MarioKart64ElementHub.Instance.AdvanceNewElementOffset(textureBlock); } else { texture.FileOffset = MarioKart64ElementHub.Instance.NewElementOffset; RomProject.Instance.Files[0].AddElement(texture); MarioKart64ElementHub.Instance.AdvanceNewElementOffset(texture); } if (palette != null) { if (paletteBlock != null) { paletteBlock.FileOffset = MarioKart64ElementHub.Instance.NewElementOffset; RomProject.Instance.Files[0].AddElement(paletteBlock); MarioKart64ElementHub.Instance.AdvanceNewElementOffset(paletteBlock); } else { palette.FileOffset = MarioKart64ElementHub.Instance.NewElementOffset; RomProject.Instance.Files[0].AddElement(palette); MarioKart64ElementHub.Instance.AdvanceNewElementOffset(palette); } } //Add in the new MK64Image int tFileOffset = (textureBlock == null ? texture.FileOffset : textureBlock.FileOffset); MK64Image.MK64ImageEncoding tEncoding = (textureBlock == null ? MK64Image.MK64ImageEncoding.Raw : MK64Image.MK64ImageEncoding.MIO0); int tBlockOffset = (textureBlock == null ? -1 : texture.FileOffset); List <int> PaletteOffset = new List <int>(); List <MK64Image.MK64ImageEncoding> PaletteEncodings = new List <MK64Image.MK64ImageEncoding>(); List <int> PaletteBlockOffset = new List <int>(); List <int> PaletteColorCount = new List <int>(); List <int> PaletteColorOffset = new List <int>(); if (palette != null) { PaletteOffset.Add(paletteBlock == null ? palette.FileOffset : paletteBlock.FileOffset); PaletteEncodings.Add(paletteBlock == null ? MK64Image.MK64ImageEncoding.Raw : MK64Image.MK64ImageEncoding.MIO0); PaletteBlockOffset.Add(paletteBlock == null ? -1 : palette.FileOffset); PaletteColorCount.Add(palette.Colors.Length); PaletteColorOffset.Add(0); } MK64Image newImage = new MK64Image(tFileOffset, tEncoding, tBlockOffset, _newImageForm.Format, _newImageForm.PixelSize, bmp.Width, bmp.Height, false, PaletteOffset, PaletteEncodings, PaletteBlockOffset, PaletteColorCount, PaletteColorOffset, 0, 0, Path.GetFileNameWithoutExtension(FileName)); MarioKart64ElementHub.Instance.TextureHub.AddImage(newImage); newImages.Add(newImage); } if (newImages.Count > 1) { MessageBox.Show(string.Format("{0} images loaded!", newImages.Count), "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } if (newImages.Count > 0) { int newSelectedIndex = lbImages.Items.Count; lbImages.Items.AddRange(newImages.ToArray()); //Update the image count & selected lbImages.SelectedIndex = newSelectedIndex; UpdateImageCount(); } } }