/// <summary> /// Encodes a PICA200 Texture. /// </summary> /// <param name="img">Input image to be encoded</param> /// <param name="format">Pixel Format of the Texture</param> /// <returns></returns> public static byte[] encode(Bitmap img, RenderBase.OTextureFormat format) { byte[] data = TextureUtils.getArray(img); byte[] output = new byte[data.Length]; uint outputOffset = 0; switch (format) { case RenderBase.OTextureFormat.rgba8: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + ((tY * 8 + y) * img.Width)) * 4; Buffer.BlockCopy(data, (int)dataOffset, output, (int)outputOffset + 1, 3); output[outputOffset] = data[dataOffset + 3]; outputOffset += 4; } } } break; default: throw new NotImplementedException(); } return(output); }
/// <summary> /// Encodes a PICA200 Texture. /// </summary> /// <param name="img">Input image to be encoded</param> /// <param name="format">Pixel Format of the Texture</param> /// <returns></returns> public static byte[] encode(Bitmap img, RenderBase.OTextureFormat format) { byte[] data = TextureUtils.getArray(img); byte[] output = new byte[data.Length]; bool toggle = false; uint outputOffset = 0; switch (format) { case RenderBase.OTextureFormat.rgba8: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + ((tY * 8 + y) * img.Width)) * 4; byte b = (byte)(data[dataOffset]); byte g = (byte)(data[dataOffset + 1]); byte r = (byte)(data[dataOffset + 2]); output[outputOffset + 1] = b; output[outputOffset + 2] = g; output[outputOffset + 3] = r; output[outputOffset] = data[dataOffset + 3]; outputOffset += 4; } } } break; case RenderBase.OTextureFormat.rgb8: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + ((tY * 8 + y) * img.Width)) * 4; byte b = (byte)(data[dataOffset]); byte g = (byte)(data[dataOffset + 1]); byte r = (byte)(data[dataOffset + 2]); output[outputOffset] = b; output[outputOffset + 1] = g; output[outputOffset + 2] = r; outputOffset += 3; } } } break; case RenderBase.OTextureFormat.rgba5551: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; ulong pixelData = (ulong)(data[dataOffset]); byte b = (byte)(data[dataOffset]); byte g = (byte)(data[dataOffset + 1]); byte r = (byte)(data[dataOffset + 2]); byte a = (byte)(data[dataOffset + 3]); output[outputOffset] = (byte)((((g >> 3) & 3) << 6) + ((b >> 3) << 1) + (a & 1)); output[outputOffset + 1] = (byte)(((r >> 3) << 3) + (g >> 5)); outputOffset += 2; } } } break; case RenderBase.OTextureFormat.rgb565: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; byte b = (byte)(data[dataOffset] / 8); byte g = (byte)(data[dataOffset + 1] / 4); byte r = (byte)(data[dataOffset + 2] / 8); output[outputOffset] = (byte)(((g & 7) << 5) | b); output[outputOffset + 1] = (byte)((r << 3) | ((g & 0x38) >> 3)); outputOffset += 2; } } } break; case RenderBase.OTextureFormat.rgba4: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; byte b = (byte)(data[dataOffset] / 16); byte g = (byte)(data[dataOffset + 1] / 16); byte r = (byte)(data[dataOffset + 2] / 16); byte a = (byte)(data[dataOffset + 3] / 16); output[outputOffset + 1] = (byte)((r << 4) | g); output[outputOffset] = (byte)((b << 4) | a); outputOffset += 2; } } } break; case RenderBase.OTextureFormat.la8: case RenderBase.OTextureFormat.hilo8: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; output[outputOffset] = data[dataOffset]; output[outputOffset + 1] = data[dataOffset + 3]; outputOffset += 2; } } } break; case RenderBase.OTextureFormat.l8: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; output[outputOffset] = data[dataOffset]; outputOffset++; } } } break; case RenderBase.OTextureFormat.a8: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; output[outputOffset] = data[dataOffset + 3]; outputOffset++; } } } break; case RenderBase.OTextureFormat.la4: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; output[outputOffset] = (byte)((data[dataOffset] / 16) << 4 | data[dataOffset + 3] / 16); outputOffset++; } } } break; case RenderBase.OTextureFormat.l4: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; byte c = (byte)(data[dataOffset++] >> 4); byte wholeByte = 0; if (toggle) { wholeByte = (byte)((wholeByte << 4) | (data[dataOffset++] >> 4)); output[outputOffset] = wholeByte; outputOffset++; } else { wholeByte = c; } toggle = !toggle; } } } break; case RenderBase.OTextureFormat.a4: for (int tY = 0; tY < img.Height / 8; tY++) { for (int tX = 0; tX < img.Width / 8; tX++) { for (int pixel = 0; pixel < 64; pixel++) { int x = tileOrder[pixel] % 8; int y = (tileOrder[pixel] - x) / 8; long dataOffset = ((tX * 8) + x + (((tY * 8 + y)) * img.Width)) * 4; byte c = (byte)(data[dataOffset + 3] >> 4); byte wholeByte = 0; if (toggle) { wholeByte = (byte)((wholeByte << 4) | (data[dataOffset++] >> 4)); output[outputOffset] = wholeByte; outputOffset++; } else { wholeByte = c; } toggle = !toggle; } } } break; case RenderBase.OTextureFormat.etc1: case RenderBase.OTextureFormat.etc1a4: int[] etc1Order = etc1Scramble(img.Width, img.Height); int i = 0; for (int tY = 0; tY < img.Height / 4; tY++) { for (int tX = 0; tX < img.Width / 4; tX++) { int TX = etc1Order[i] % (img.Width / 4); int TY = (etc1Order[i] - TX) / (img.Width / 4); outputOffset = (uint)((TX * 4) + (((TY * 4)) * (img.Width / 4))) * 2; if (format == RenderBase.OTextureFormat.etc1a4) { outputOffset = (uint)((TX * 4) + (((TY * 4)) * (img.Width / 4))) * 4; ulong alpha = 0; int iiii = 0; for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { long dataOffset = ((tX * 4) + (x) + (((tY * 4) + (y)) * img.Width)) * 4; uint a = (uint)data[dataOffset + 3] / 16; alpha |= (ulong)a << (iiii); iiii += 4; } } output[outputOffset + 7] = (byte)((alpha >> 56) & 0xFF); output[outputOffset + 6] = (byte)((alpha >> 48) & 0xFF); output[outputOffset + 5] = (byte)((alpha >> 40) & 0xFF); output[outputOffset + 4] = (byte)((alpha >> 32) & 0xFF); output[outputOffset + 3] = (byte)((alpha >> 24) & 0xFF); output[outputOffset + 2] = (byte)((alpha >> 16) & 0xFF); output[outputOffset + 1] = (byte)((alpha >> 8) & 0xFF); output[outputOffset] = (byte)(alpha & 0xFF); outputOffset += 8; } Color[] pixels = new Color[4 * 4]; for (int yy = 0; yy < 4; yy++) { for (int xx = 0; xx < 4; xx++) { long dataOffset = ((tX * 4) + (xx) + (((tY * 4) + (yy)) * img.Width)) * 4; //if (TX + xx >= img.Width) pixels[yy * 4 + xx] = Color.Transparent; //else if (TY + yy >= img.Height) pixels[yy * 4 + xx] = Color.Transparent; pixels[yy * 4 + xx] = Color.FromArgb((int)data[dataOffset + 0] | (int)data[dataOffset + 1] << 8 | (int)data[dataOffset + 2] << 16 | (int)data[dataOffset + 3] << 24); } } ulong ETC1Chunk = ETC1.GenETC1(pixels); output[outputOffset + 7] = (byte)((ETC1Chunk >> 56) & 0xFF); output[outputOffset + 6] = (byte)((ETC1Chunk >> 48) & 0xFF); output[outputOffset + 5] = (byte)((ETC1Chunk >> 40) & 0xFF); output[outputOffset + 4] = (byte)((ETC1Chunk >> 32) & 0xFF); output[outputOffset + 3] = (byte)((ETC1Chunk >> 24) & 0xFF); output[outputOffset + 2] = (byte)((ETC1Chunk >> 16) & 0xFF); output[outputOffset + 1] = (byte)((ETC1Chunk >> 8) & 0xFF); output[outputOffset + 0] = (byte)(ETC1Chunk & 0xFF); outputOffset += 8; i += 1; } } break; default: throw new NotImplementedException(); } return(output); }