private void ConvertToI4(Bitmap imageToConvert) { SetupCoder(imageToConvert); /* We will need to add a grayscale check in the future also */ if (UniqueColors.Count > 16) { WuQuantizer quantizer = new WuQuantizer(); imageToConvert = new Bitmap(quantizer.QuantizeImage(imageToConvert, 0, 0, new Histogram(), 16)); SetupCoder(imageToConvert); } /* Set type, I 4-bit */ Format = GBI.G_IM_FMT_I; Size = GBI.G_IM_SIZ_4b; n64ImageType = N64ImageType.i4; /* Generate texture buffer */ Data = new byte[(imageToConvert.Width * imageToConvert.Height) / 2]; Palette = null; /* Loop through pixels, convert to I 4-bit, write to texture buffer */ for (int i = 0, j = 0; i < Raw.Length; i += 8, j++) { Data[j] = (byte)(((Raw[i] / 16) << 4) | ((Raw[i + 4] / 16) & 0xF)); } }
private void ConvertToCi4(Bitmap imageToConvert) { /* Convert to CI */ if (UniqueColors.Count > 16) { WuQuantizer quantizer = new WuQuantizer(); imageToConvert = new Bitmap(quantizer.QuantizeImage(imageToConvert, 0, 0, new Histogram(), 16)); SetupCoder(imageToConvert); } /* Set type, CI 4-bit */ Format = GBI.G_IM_FMT_CI; Size = GBI.G_IM_SIZ_4b; n64ImageType = N64ImageType.ci4; /* Generate texture buffer */ Data = new byte[(imageToConvert.Width * imageToConvert.Height) / 2]; /* Generate 16-color RGBA5551 palette */ Palette = GeneratePalette(UniqueColors, 16); /* Loop through pixels, get palette indexes, write to texture buffer */ for (int i = 0, j = 0; i < Raw.Length; i += 8, j++) { ushort RGBA5551_1 = ToRGBA5551(Raw[i + 2], Raw[i + 1], Raw[i], Raw[i + 3]); ushort RGBA5551_2 = ToRGBA5551(Raw[i + 6], Raw[i + 5], Raw[i + 4], Raw[i + 7]); byte Value = (byte)( ((GetPaletteIndex(Palette, RGBA5551_1)) << 4) | ((GetPaletteIndex(Palette, RGBA5551_2) & 0xF))); Data[j] = Value; } }
private void ConvertToCi8(Bitmap imageToConvert) { if (UniqueColors.Count > 256) { WuQuantizer quantizer = new WuQuantizer(); imageToConvert = new Bitmap(quantizer.QuantizeImage(imageToConvert, 0, 0, new Histogram(), 256)); SetupCoder(imageToConvert); } /* Set type, CI 8-bit */ Format = GBI.G_IM_FMT_CI; Size = GBI.G_IM_SIZ_8b; n64ImageType = N64ImageType.ci8; /* Generate texture buffer * NFL BLitz requires CI8 to be padded to 8 bytes */ int dataSize = (imageToConvert.Width * imageToConvert.Height); while (dataSize % 8 != 0) { dataSize++; } Data = new byte[dataSize]; /* Generate 256-color RGBA5551 palette */ Palette = GeneratePalette(UniqueColors, 256); /* Loop through pixels, get palette indexes, write to texture buffer */ for (int i = 0, j = 0; i < Raw.Length; i += 4, j++) { ushort RGBA5551 = ToRGBA5551(Raw[i + 2], Raw[i + 1], Raw[i], Raw[i + 3]); Data[j] = (byte)GetPaletteIndex(Palette, RGBA5551); } }
private void ConvertToc16PlusI4(Bitmap imageToConvert) { //split image in half Bitmap c16, i4; c16 = i4 = new Bitmap(imageToConvert.Width, imageToConvert.Height / 2); Rectangle rect = new Rectangle(0, 0, imageToConvert.Width, imageToConvert.Height / 2); c16 = imageToConvert.Clone(rect, imageToConvert.PixelFormat); rect = new Rectangle(0, imageToConvert.Height / 2, imageToConvert.Width, imageToConvert.Height / 2); i4 = imageToConvert.Clone(rect, imageToConvert.PixelFormat); ImageCoder c16ImageCoder = new ImageCoder(); c16ImageCoder = new N64ImageViewer.ImageCoder(); c16ImageCoder.ConvertToC16(c16); ImageCoder i4ImageCoder = new ImageCoder(); i4ImageCoder.ConvertToI4(i4); n64ImageType = N64ImageType.c16PlusI4; List <byte> tempData = new List <byte>(); tempData.AddRange(c16ImageCoder.Data); tempData.AddRange(i4ImageCoder.Data); Data = tempData.ToArray(); Width = imageToConvert.Width; // Height is used for both the C16 and I4 so we need to split it in half, since each image makes up half Height = imageToConvert.Height / 2; HasAlpha = c16ImageCoder.HasAlpha; return; }
private void ConvertToia8(Bitmap imageToConvert) { /* Set type, IA 8-bit */ Format = GBI.G_IM_FMT_IA; Size = GBI.G_IM_SIZ_8b; n64ImageType = N64ImageType.ia8; /* Generate texture buffer */ Data = new byte[imageToConvert.Width * imageToConvert.Height]; Palette = null; /* Loop through pixels, convert to IA 8-bit, write to texture buffer */ for (int i = 0, j = 0; i < Raw.Length; i += 4, j++) { Data[j] = (byte)(((Raw[i] / 16) << 4) | ((Raw[i + 3] / 16) & 0xF)); } }
private void ConvertToI8(Bitmap imageToConvert) { /* Set type, I 8-bit */ Format = GBI.G_IM_FMT_I; Size = GBI.G_IM_SIZ_8b; n64ImageType = N64ImageType.notSupported; //NFL Blitz does not make use of I8 Images /* Generate texture buffer */ Data = new byte[imageToConvert.Width * imageToConvert.Height]; Palette = null; /* Loop through pixels, convert to I 8-bit, write to texture buffer */ for (int i = 0, j = 0; i < Raw.Length; i += 4, j++) { Data[j] = Raw[i]; } }
private void ConvertToC16(Bitmap imageToConvert) { SetupCoder(imageToConvert); /* Set type, RGBA 16-bit */ Format = GBI.G_IM_FMT_RGBA; Size = GBI.G_IM_SIZ_16b; n64ImageType = N64ImageType.c16; /* Generate texture buffer */ Data = new byte[imageToConvert.Width * imageToConvert.Height * 2]; Palette = null; /* Loop through pixels, convert to RGBA5551, write to texture buffer */ for (int i = 0, j = 0; i < Raw.Length; i += 4, j += 2) { ushort RGBA5551 = ToRGBA5551(Raw[i + 2], Raw[i + 1], Raw[i], Raw[i + 3]); Data[j] = (byte)(RGBA5551 >> 8); Data[j + 1] = (byte)(RGBA5551 & 0xFF); } }
public void ConvertTo(Bitmap imageToConvert, N64ImageType type) { SetupCoder(imageToConvert); switch (type) { case N64ImageType.c16: { ConvertToC16(imageToConvert); return; }; case N64ImageType.ci8: { ConvertToCi8(imageToConvert); return; } case N64ImageType.c16PlusI4: { ConvertToc16PlusI4(imageToConvert); return; } } }
/// <summary> /// Converts given ObjFile.imageToConvert into N64 texture /// </summary> /// <param name="imageToConvert">imageToConvert to convert</param> public void Convert(Bitmap imageToConvert, bool checkC16I4 = true) { // C16-I4 Check, Pretty hacky... if (checkC16I4 && imageToConvert.Height % 2 == 0) { //even height, split it in half Bitmap c16, i4; c16 = i4 = new Bitmap(imageToConvert.Width, imageToConvert.Height / 2); Rectangle rect = new Rectangle(0, 0, imageToConvert.Width, imageToConvert.Height / 2); c16 = imageToConvert.Clone(rect, imageToConvert.PixelFormat); rect = new Rectangle(0, imageToConvert.Height / 2, imageToConvert.Width, imageToConvert.Height / 2); i4 = imageToConvert.Clone(rect, imageToConvert.PixelFormat); ImageCoder c16ImageCoder = new ImageCoder(); c16ImageCoder = new N64ImageViewer.ImageCoder(); c16ImageCoder.Convert(c16, false); ImageCoder i4ImageCoder = new ImageCoder(); i4ImageCoder.Convert(i4, false); if (c16ImageCoder.n64ImageType.Equals(N64ImageType.c16) && i4ImageCoder.n64ImageType.Equals(N64ImageType.i4)) { n64ImageType = N64ImageType.c16PlusI4; List <byte> tempData = new List <byte>(); tempData.AddRange(c16ImageCoder.Data); tempData.AddRange(i4ImageCoder.Data); Data = tempData.ToArray(); Width = imageToConvert.Width; Height = imageToConvert.Height / 2; // Height is used for both the C16 and I4 so we need to split it in half, since each image makes up half HasAlpha = c16ImageCoder.HasAlpha; return; } } //End C16-I4 check try { SetupCoder(imageToConvert); if (IsGrayscale == true) { if (HasAlpha == true) { /* Convert to IA */ if (UniqueColors.Count <= 16) { ConvertToia8(imageToConvert); } } else { /* Convert to I */ if (UniqueColors.Count <= 16) { ConvertToI4(imageToConvert); } else if (UniqueColors.Count <= 256 && imageToConvert.Width * imageToConvert.Height <= 4096) { ConvertToI8(imageToConvert); } else { /* Uh-oh, too many grayshades OR invalid size! */ throw new Exception("Too many grayshades in texture OR invalid size"); } } } else { /* Convert to CI */ if (UniqueColors.Count <= 16) { ConvertToCi4(imageToConvert); } else if (UniqueColors.Count <= 256) { ConvertToCi8(imageToConvert); } else { ConvertToC16(imageToConvert); } } } catch (Exception ex) { // System.Windows.Forms.MessageBox.Show("imageToConvert '" + imageToConvert.DisplayName + "': " + ex.Message, "Exception", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation); // SetInvalidTexture(imageToConvert); } /* Pack texture type */ Type = (byte)((Format << 5) | (Size << 3)); }