public static string CodecString(N64Codec codec) { switch (codec) { case N64Codec.RGBA16: return("rgba16"); case N64Codec.RGBA32: return("rgba32"); case N64Codec.IA16: return("ia16"); case N64Codec.IA8: return("ia8"); case N64Codec.IA4: return("ia4"); case N64Codec.I8: return("i8"); case N64Codec.I4: return("i4"); case N64Codec.CI8: return("ci8"); case N64Codec.CI4: return("ci4"); case N64Codec.ONEBPP: return("1bpp"); } return("unk"); }
private static N64Codec WhichCodec(int idx) { N64Codec viewerCodec = N64Codec.RGBA16; switch (idx) { case 0: viewerCodec = N64Codec.RGBA16; break; case 1: viewerCodec = N64Codec.RGBA32; break; case 2: viewerCodec = N64Codec.IA16; break; case 3: viewerCodec = N64Codec.IA8; break; case 4: viewerCodec = N64Codec.IA4; break; case 5: viewerCodec = N64Codec.I8; break; case 6: viewerCodec = N64Codec.I4; break; case 7: viewerCodec = N64Codec.CI8; break; case 8: viewerCodec = N64Codec.CI4; break; case 9: viewerCodec = N64Codec.ONEBPP; break; } return(viewerCodec); }
// return number of bytes needed to encode numPixels using codec public static int PixelsToBytes(N64Codec codec, int numPixels) { int numBytes = 0; switch (codec) { case N64Codec.RGBA16: numBytes = numPixels * 2; break; case N64Codec.RGBA32: numBytes = numPixels * 4; break; case N64Codec.IA16: numBytes = numPixels * 2; break; case N64Codec.IA8: numBytes = numPixels; break; case N64Codec.IA4: numBytes = numPixels / 2; break; case N64Codec.I8: numBytes = numPixels; break; case N64Codec.I4: numBytes = numPixels / 2; break; case N64Codec.CI8: numBytes = numPixels; break; case N64Codec.CI4: numBytes = numPixels / 2; break; case N64Codec.ONEBPP: numBytes = numPixels / 8; break; } return(numBytes); }
private void toolStripCodec_SelectedIndexChanged(object sender, EventArgs e) { N64Codec prevCodec = viewerCodec; viewerCodec = N64Codec.RGBA16; switch (toolStripCodec.SelectedIndex) { case 0: viewerCodec = N64Codec.RGBA16; break; case 1: viewerCodec = N64Codec.RGBA32; break; case 2: viewerCodec = N64Codec.IA16; break; case 3: viewerCodec = N64Codec.IA8; break; case 4: viewerCodec = N64Codec.IA4; break; case 5: viewerCodec = N64Codec.I8; break; case 6: viewerCodec = N64Codec.I4; break; case 7: viewerCodec = N64Codec.CI8; break; case 8: viewerCodec = N64Codec.CI4; break; case 9: viewerCodec = N64Codec.ONEBPP; break; } if (prevCodec != viewerCodec) { foreach (GraphicsViewer gv in viewers) { gv.Codec = viewerCodec; gv.Invalidate(); } switch (viewerCodec) { case N64Codec.CI8: gviewPalette.PixScale = 8; break; case N64Codec.CI4: gviewPalette.PixScale = 32; break; } gviewPalette.Invalidate(); groupBoxPalette.Visible = viewerCodec == N64Codec.CI8 || viewerCodec == N64Codec.CI4; toolStripAlpha.Enabled = viewerCodec == N64Codec.I8 || viewerCodec == N64Codec.I4; } }
public static void FromColor(Color color, out byte[] data, N64Codec codec) { switch (codec) { case N64Codec.RGBA16: data = new byte[2]; ColorRGBA16(color, out data[0], out data[1]); break; case N64Codec.RGBA32: data = new byte[] { color.R, color.G, color.B, color.A }; break; default: data = new byte[] { }; break; } }
private void InjectIMGBut_Click(object sender, EventArgs e) { OpenFileDialog open = new OpenFileDialog(); open.Filter = "bin file|*.bin"; DialogResult res = open.ShowDialog(); if (res == DialogResult.OK) { byte[] binfile = File.ReadAllBytes(open.FileName); Injector inj = new Injector(); N64Codec codec = N64Codec.CI4; switch (SelectedCodec.SelectedItem) { case ("CI4"): { codec = N64Codec.CI4; break; } case ("CI8"): { codec = N64Codec.CI8; break; } } open.Filter = "bitmap file|*.bmp|png file|*.png|jpg file|*.jpg"; res = open.ShowDialog(); if (res == DialogResult.OK) { Bitmap bmp = new Bitmap(open.FileName); byte[] OutPut = inj.InjectImageIntoByteArray((int)ImgNum.Value, (int)PalleteNum.Value, binfile, bmp, codec); SaveFileDialog save = new SaveFileDialog(); save.Filter = "bin file|*.bin"; res = save.ShowDialog(); if (res == DialogResult.OK) { File.WriteAllBytes(save.FileName, OutPut); } } } }
public static void Convert(ref byte[] imageData, ref byte[] paletteData, N64Codec codec, Bitmap bm) { int numPixels = bm.Width * bm.Height; imageData = new byte[PixelsToBytes(codec, numPixels)]; int palCount = 0; switch (codec) { case N64Codec.RGBA16: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); byte r, g, b; r = SCALE_8_5(col.R); g = SCALE_8_5(col.G); b = SCALE_8_5(col.B); byte c0 = (byte)((r << 3) | (g >> 2)); byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); int idx = 2 * (y * bm.Width + x); imageData[idx + 0] = c0; imageData[idx + 1] = c1; } } break; case N64Codec.RGBA32: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int idx = 4 * (y * bm.Width + x); imageData[idx + 0] = col.R; imageData[idx + 1] = col.G; imageData[idx + 2] = col.B; imageData[idx + 3] = col.A; } } break; case N64Codec.IA16: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int sum = col.R + col.G + col.B; byte intensity = (byte)(sum / 3); byte alpha = col.A; int idx = 2 * (y * bm.Width + x); imageData[idx + 0] = intensity; imageData[idx + 1] = alpha; } } break; case N64Codec.IA8: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int sum = col.R + col.G + col.B; byte intensity = SCALE_8_4((byte)(sum / 3)); byte alpha = SCALE_8_4(col.A); int idx = y * bm.Width + x; imageData[idx] = (byte)((intensity << 4) | alpha); } } break; case N64Codec.IA4: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int sum = col.R + col.G + col.B; byte intensity = SCALE_8_3((byte)(sum / 3)); byte alpha = (byte)(col.A > 0 ? 1 : 0); int idx = y * bm.Width + x; byte old = imageData[idx / 2]; if ((idx % 2) > 0) { imageData[idx / 2] = (byte)((old & 0xF0) | (intensity << 1) | alpha); } else { imageData[idx / 2] = (byte)((old & 0x0F) | (((intensity << 1) | alpha) << 4)); } } } break; case N64Codec.I8: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int sum = col.R + col.G + col.B; byte intensity = (byte)(sum / 3); int idx = y * bm.Width + x; imageData[idx] = intensity; } } break; case N64Codec.I4: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int sum = col.R + col.G + col.B; byte intensity = SCALE_8_4((byte)(sum / 3)); int idx = y * bm.Width + x; byte old = imageData[idx / 2]; if ((idx % 2) > 0) { imageData[idx / 2] = (byte)((old & 0xF0) | intensity); } else { imageData[idx / 2] = (byte)((old & 0x0F) | (intensity << 4)); } } } break; case N64Codec.CI4: paletteData = new byte[16 * 2]; for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); byte r, g, b; r = SCALE_8_5(col.R); g = SCALE_8_5(col.G); b = SCALE_8_5(col.B); byte c0 = (byte)((r << 3) | (g >> 2)); byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); int idx = y * bm.Width + x; int palIdx = paletteIndex(paletteData, palCount, c0, c1); if (palIdx < 0) { if (palCount < paletteData.Length / 2) { palIdx = palCount; paletteData[2 * palCount] = c0; paletteData[2 * palCount + 1] = c1; palCount++; } else { palIdx = 0; // TODO: out of palette entries. error or pick closest? } } byte old = imageData[idx / 2]; if ((idx % 2) > 0) { imageData[idx / 2] = (byte)((old & 0xF0) | (byte)palIdx); } else { imageData[idx / 2] = (byte)((old & 0x0F) | ((byte)palIdx << 4)); } } } break; case N64Codec.CI8: paletteData = new byte[256 * 2]; for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); byte r, g, b; r = SCALE_8_5(col.R); g = SCALE_8_5(col.G); b = SCALE_8_5(col.B); byte c0 = (byte)((r << 3) | (g >> 2)); byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0)); int idx = y * bm.Width + x; int palIdx = paletteIndex(paletteData, palCount, c0, c1); if (palIdx < 0) { if (palCount < paletteData.Length / 2) { palIdx = palCount; paletteData[2 * palCount] = c0; paletteData[2 * palCount + 1] = c1; palCount++; } else { palIdx = 0; // TODO: out of palette entries. error or pick closest? } } imageData[idx] = (byte)palIdx; } } break; case N64Codec.ONEBPP: for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { Color col = bm.GetPixel(x, y); int sum = col.R + col.G + col.B; byte intensity = (sum > 0) ? (byte)1 : (byte)0; int idx = y * bm.Width + x; byte old = imageData[idx / 8]; int bit = idx % 8; int mask = ~(1 << bit); imageData[idx / 8] = (byte)((old & mask) | (intensity << bit)); } } break; } }
public static void RenderTexture(Graphics g, byte[] data, byte[] palette, int offset, int width, int height, int scale, N64Codec codec, N64IMode mode) { Brush brush; for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { int pixOffset = (h * width + w); int bytesPerPix = 1; int select = 0; switch (codec) { case N64Codec.RGBA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break; case N64Codec.RGBA32: bytesPerPix = 4; pixOffset *= bytesPerPix; break; case N64Codec.IA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break; case N64Codec.IA8: break; case N64Codec.IA4: select = pixOffset & 0x1; pixOffset /= 2; break; case N64Codec.I8: break; case N64Codec.I4: case N64Codec.CI4: select = pixOffset & 0x1; pixOffset /= 2; break; case N64Codec.CI8: break; case N64Codec.ONEBPP: select = pixOffset & 0x7; pixOffset /= 8; break; } pixOffset += offset; if (data.Length > pixOffset + bytesPerPix - 1) { brush = new SolidBrush(MakeColor(data, palette, pixOffset, select, codec, mode)); g.FillRectangle(brush, w * scale, h * scale, scale, scale); } } } }
public static Color MakeColor(byte[] data, byte[] palette, int offset, int select, N64Codec codec, N64IMode mode) { Color color; switch (codec) { case N64Codec.RGBA16: color = RGBA16Color(data, offset); break; case N64Codec.RGBA32: color = RGBA32Color(data, offset); break; case N64Codec.IA16: color = IA16Color(data, offset); break; case N64Codec.IA8: color = IA8Color(data, offset); break; case N64Codec.IA4: color = IA4Color(data, offset, select); break; case N64Codec.I8: color = I8Color(data, offset, mode); break; case N64Codec.I4: color = I4Color(data, offset, select, mode); break; case N64Codec.CI8: color = CI8Color(data, palette, offset); break; case N64Codec.CI4: color = CI4Color(data, palette, offset, select); break; case N64Codec.ONEBPP: color = BPPColor(data, offset, select); break; default: color = RGBA16Color(data, offset); break; } return(color); }
//This works fine as shared /// <summary> /// Injects a custom bitmap into a .bin file /// </summary> /// <param name="OriginalData">The original file we want to import our image into</param> /// <param name="Image">Our image to import</param> /// <param name="Codec">The N64Codec to use</param> /// <param name="ImageOffset">The offset of the image within the file</param> /// <param name="PaletteOffset">The offset of the palette within the file</param> public byte[] InjectImageIntoByteArray(int ImageOffset, int PaletteOffset, byte[] OriginalData, Bitmap Image, N64Codec Codec) { byte[] imageData = null, paletteData = null; N64GraphicsCoding.Convert(ref imageData, ref paletteData, Codec, Image); ByteTools.TrimEnd(paletteData); Array.Copy(imageData, 0, OriginalData, ImageOffset, imageData.Length); Array.Copy(paletteData, 0, OriginalData, PaletteOffset, paletteData.Length); return(OriginalData); }
private void runTest(int idx, bool verbose, PictureBox pbIn, PictureBox pbOut) { int width = 32; int height = 32; byte[] test = new byte[width * height * 4]; // worst case byte[] result = null; byte[] pal = new byte[16 * 16 * 2]; byte[] resultPal = null; int errorCount = 0; StringBuilder sb = new StringBuilder(); N64Codec testCodec = WhichCodec(idx); // randomize inputs Random rng = new Random(); rng.NextBytes(test); rng.NextBytes(pal); // if alpha bit clear, clear all bits switch (testCodec) { case N64Codec.RGBA16: for (int i = 0; i < test.Length; i += 2) { if ((test[i + 1] & 0x1) == 0) { test[i] = 0; test[i + 1] = 0; } } break; case N64Codec.IA16: for (int i = 0; i < test.Length; i += 2) { if ((test[i + 1]) == 0) { test[i] = 0; } } break; case N64Codec.IA8: for (int i = 0; i < test.Length; i++) { if ((test[i] & 0x0F) == 0) { test[i] = 0; } } break; case N64Codec.IA4: for (int i = 0; i < test.Length; i++) { if ((test[i] & 0x10) == 0) { test[i] &= 0x0F; } if ((test[i] & 0x01) == 0) { test[i] &= 0xF0; } } break; case N64Codec.CI4: case N64Codec.CI8: for (int i = 0; i < pal.Length; i += 2) { if ((pal[i + 1] & 0x1) == 0) { pal[i] = 0; pal[i + 1] = 0; } } break; } Bitmap b = new Bitmap(width, height, PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(b); N64Graphics.RenderTexture(g, test, pal, 0, width, height, 1, testCodec, N64IMode.AlphaCopyIntensity); N64Graphics.Convert(ref result, ref resultPal, testCodec, b); Bitmap bres = new Bitmap(width, height, PixelFormat.Format32bppArgb); N64Graphics.RenderTexture(Graphics.FromImage(bres), result, resultPal, 0, width, height, 1, testCodec, N64IMode.AlphaCopyIntensity); for (int i = 0; i < result.Length; i++) { if (test[i] != result[i]) { errorCount++; } if (verbose) { sb.AppendFormat("{0:X03} {1:X02} {2:X02}\r\n", i, test[i], result[i]); } } if (resultPal != null) { for (int i = 0; i < resultPal.Length; i++) { if (pal[i] != resultPal[i]) { errorCount++; } if (verbose) { sb.AppendFormat("P {0:X03} {1:X02} {2:X02}\r\n", i, pal[i], resultPal[i]); } } } // publish results sb.AppendFormat("Test[{0}] {1}: {2} errors\r\n", idx, N64Graphics.CodecString(testCodec), errorCount); textBoxLog.AppendText(sb.ToString()); pbIn.Image = b; pbOut.Image = bres; }