/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="texFmt"></param> /// <param name="palFmt"></param> public static bool FormatFromString(string name, out GXTexFmt texFmt, out GXTlutFmt palFmt) { texFmt = GXTexFmt.RGBA8; palFmt = GXTlutFmt.RGB5A3; var parts = Path.GetFileNameWithoutExtension(name).Split('_'); bool foundFormat = false; foreach (var p in parts) { // skip numeric values if (int.TryParse(p, out int i)) { continue; } if (Enum.TryParse(p.ToUpper(), out GXTexFmt format)) { texFmt = format; foundFormat = true; } if (Enum.TryParse(p.ToUpper(), out GXTlutFmt palFormat)) { palFmt = palFormat; } } return(foundFormat); }
/// <summary> /// /// </summary> /// <param name="tobj"></param> /// <param name="bmp"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> public static void InjectBitmap(Bitmap bmp, HSD_TOBJ tobj, GXTexFmt imgFormat, GXTlutFmt palFormat) { if (imgFormat == GXTexFmt.CI8) // doesn't work well with alpha { bmp = BitmapTools.ReduceColors(bmp, 256); } if (imgFormat == GXTexFmt.CI4 || imgFormat == GXTexFmt.CI14X2) { bmp = BitmapTools.ReduceColors(bmp, 16); } var bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var length = bitmapData.Stride * bitmapData.Height; byte[] bytes = new byte[length]; Marshal.Copy(bitmapData.Scan0, bytes, 0, length); bmp.UnlockBits(bitmapData); tobj.EncodeImageData(bytes, bmp.Width, bmp.Height, imgFormat, palFormat); // dispose if we use our color reduced bitmap //if (imgFormat == GXTexFmt.CI8 || imgFormat == GXTexFmt.CI4 || imgFormat == GXTexFmt.CI14X2) // bmp.Dispose(); }
private static byte[] ImageToTPL(uint[] rgba, int width, int height, GXTexFmt tplFormat) { switch (tplFormat) { case GXTexFmt.I4: return(toI4(rgba, width, height)); case GXTexFmt.I8: return(toI8(rgba, width, height)); case GXTexFmt.IA4: return(toIA4(rgba, width, height)); case GXTexFmt.IA8: return(toIA8(rgba, width, height)); case GXTexFmt.RGB565: return(toRGB565(rgba, width, height)); case GXTexFmt.RGB5A3: return(toRGB5A3(rgba, width, height)); case GXTexFmt.RGBA8: return(toRGBA8(rgba, width, height)); case GXTexFmt.CI4: case GXTexFmt.CI8: case GXTexFmt.CI14X2: case GXTexFmt.CMP: return(new byte[0]); default: throw new FormatException(tplFormat.ToString() + " - Format not supported!\nCurrently, images can only be converted to the following formats:\nI4, I8, IA4, IA8, RGB565, RGB5A3, RGBA8, CI4, CI8 , CI14X2."); } }
public ColorIndexConverter(uint[] rgbaData, int width, int height, GXTexFmt tplFormat, GXTlutFmt paletteFormat) { if (tplFormat != GXTexFmt.CI4 && tplFormat != GXTexFmt.CI8) // && tplFormat != TPL_TextureFormat.CI14X2) { throw new Exception("Texture format must be either CI4 or CI8"); // or CI14X2!"); } if (paletteFormat != GXTlutFmt.IA8 && paletteFormat != GXTlutFmt.RGB565 && paletteFormat != GXTlutFmt.RGB5A3) { throw new Exception("Palette format must be either IA8, RGB565 or RGB5A3!"); } this.rgbaData = rgbaData; this.width = width; this.height = height; this.tplFormat = tplFormat; this.paletteFormat = paletteFormat; buildPalette(); if (tplFormat == GXTexFmt.CI4) { toCI4(); } else if (tplFormat == GXTexFmt.CI8) { toCI8(); } else { toCI14X2(); } }
/// <summary> /// Injects <see cref="Bitmap"/> into <see cref="HSD_TOBJ"/> /// </summary> /// <param name="tobj"></param> /// <param name="img"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> public static void InjectBitmap(HSD_TOBJ tobj, string filepath, GXTexFmt imgFormat, GXTlutFmt palFormat) { Bitmap bmp = new Bitmap(filepath); InjectBitmap(tobj, bmp, imgFormat, palFormat); bmp.Dispose(); }
/// <summary> /// /// </summary> /// <param name="tobj"></param> /// <param name="bmp"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> public static void InjectBitmap(Bitmap bmp, HSD_TOBJ tobj, GXTexFmt imgFormat, GXTlutFmt palFormat) { if (imgFormat != GXTexFmt.CMP) { // if (imgFormat == GXTexFmt.CI8) // doesn't work well with alpha // bmp = ReduceColors(bmp, 256); //if (imgFormat == GXTexFmt.CI4 || imgFormat == GXTexFmt.CI14X2) // bmp = BitmapTools.ReduceColors(bmp, 16); var bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); var length = bitmapData.Stride * bitmapData.Height; byte[] bytes = new byte[length]; Marshal.Copy(bitmapData.Scan0, bytes, 0, length); bmp.UnlockBits(bitmapData); tobj.EncodeImageData(bytes, bmp.Width, bmp.Height, imgFormat, palFormat); // dispose if we use our color reduced bitmap if (imgFormat == GXTexFmt.CI8 || imgFormat == GXTexFmt.CI4 || imgFormat == GXTexFmt.CI14X2) { bmp.Dispose(); } } else { MemoryStream stream = new MemoryStream(); bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Png); byte[] bytes = stream.ToArray(); stream.Close(); stream.Dispose(); IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length); using (var origImage = TexHelper.Instance.LoadFromWICMemory(unmanagedPointer, bytes.Length, WIC_FLAGS.NONE)) { var scratch = origImage.Compress(0, DXGI_FORMAT.BC1_UNORM, TEX_COMPRESS_FLAGS.DEFAULT, 1); var ptr = scratch.GetPixels(); var length = scratch.GetPixelsSize(); byte[] data = new byte[length]; Marshal.Copy(ptr, data, 0, (int)length); scratch.Dispose(); tobj.EncodeImageData(data, bmp.Width, bmp.Height, GXTexFmt.CMP, GXTlutFmt.IA8); } // Call unmanaged code Marshal.FreeHGlobal(unmanagedPointer); } }
public static bool IsPalettedFormat(GXTexFmt format) { if (format == GXTexFmt.CI4 || format == GXTexFmt.CI8 || format == GXTexFmt.CI14X2) { return(true); } return(false); }
public override void Open(HSDReader Reader) { uint DataOffset = Reader.ReadUInt32(); Width = Reader.ReadUInt16(); Height = Reader.ReadUInt16(); Format = (GXTexFmt)Reader.ReadUInt32(); Mipmap = Reader.ReadUInt32(); MinLOD = Reader.ReadSingle(); MaxLOD = Reader.ReadSingle(); Data = Reader.ReadBuffer(DataOffset, TPL.TextureByteSize((TPL_TextureFormat)Format, Width, Height)); }
/// <summary> /// /// </summary> /// <param name="rgba"></param> /// <param name="format"></param> /// <param name="palformat"></param> /// <param name="paletteData"></param> /// <returns></returns> public static byte[] EncodeTPL(uint[] rgba, int width, int height, GXTexFmt format, GXTlutFmt palformat, out byte[] paletteData) { paletteData = null; if (IsPalettedFormat(format)) { return(FromImage(rgba, width, height, format, palformat, out paletteData)); } else { return(FromImage(rgba, width, height, format)); } }
/// <summary> /// Injects <see cref="Bitmap"/> into <see cref="HSD_TOBJ"/> /// </summary> /// <param name="tobj"></param> /// <param name="img"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> public static void InjectBitmap(string filepath, HSD_TOBJ tobj, GXTexFmt imgFormat, GXTlutFmt palFormat) { // format override if (FormatFromString(filepath, out GXTexFmt fmt, out GXTlutFmt pal)) { palFormat = pal; imgFormat = fmt; } using (Bitmap bmp = LoadBitmapFromFile(filepath)) { InjectBitmap(bmp, tobj, imgFormat, palFormat); } }
private static byte[] FromImage(uint[] rgba, int width, int height, GXTexFmt format, GXTlutFmt palFormat, out byte[] palData) { palData = new byte[0]; if (IsPalettedFormat(format)) { ColorIndexConverter cic = new ColorIndexConverter(rgba, width, height, format, palFormat); palData = cic.Palette; return(cic.Data); } else { return(ImageToTPL(rgba, width, height, format)); } }
/// <summary> /// /// </summary> /// <param name="tobj"></param> /// <param name="bmp"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> public static void InjectBitmap(Bitmap bmp, HSD_TOBJ tobj, GXTexFmt imgFormat, GXTlutFmt palFormat) { // todo: this only works without alpha :/ /*if (imgFormat == GXTexFmt.CI8) // doesn't work well with alpha * bmp = BitmapTools.ReduceColors(bmp, 256); * if (imgFormat == GXTexFmt.CI4 || imgFormat == GXTexFmt.CI14X2) * bmp = BitmapTools.ReduceColors(bmp, 16);*/ tobj.EncodeImageData(bmp.GetBGRAData(), bmp.Width, bmp.Height, imgFormat, palFormat); // dispose if we use our color reduced bitmap //if (imgFormat == GXTexFmt.CI8 || imgFormat == GXTexFmt.CI4 || imgFormat == GXTexFmt.CI14X2) // bmp.Dispose(); }
/// <summary> /// Sets the image data from a <see cref="Bitmap"/> /// </summary> /// <param name="b"></param> public void SetFromBitmap(Bitmap b, GXTexFmt imageFormat, GXTlutFmt paletteFormat) { byte[] palData; ImageData = new HSD_Image(); ImageData.Width = (ushort)b.Width; ImageData.Height = (ushort)b.Height; ImageData.Format = imageFormat; ImageData.Data = TPL.ConvertToTextureMelee(b, (int)imageFormat, (int)paletteFormat, out palData); if (palData != null && palData.Length > 0) { Tlut = new HSD_Tlut(); Tlut.Format = paletteFormat; Tlut.ColorCount = (ushort)(palData.Length / 2); Tlut.Data = palData; } }
/// <summary> /// Import TOBJ from PNG file /// </summary> /// <returns></returns> public static HSD_TOBJ ImportTOBJFromFile(string filePath, GXTexFmt imgFmt, GXTlutFmt tlutFmt) { var TOBJ = new HSD_TOBJ() { MagFilter = GXTexFilter.GX_LINEAR, HScale = 1, WScale = 1, WrapS = GXWrapMode.CLAMP, WrapT = GXWrapMode.CLAMP, SX = 1, SY = 1, SZ = 1, GXTexGenSrc = 4, Blending = 1 }; InjectBitmap(TOBJ, filePath, imgFmt, tlutFmt); return(TOBJ); }
/// <summary> /// Import TOBJ from PNG file /// </summary> /// <returns></returns> public static HSD_TOBJ ImportTOBJFromFile(string filePath, GXTexFmt imgFmt, GXTlutFmt tlutFmt) { var TOBJ = new HSD_TOBJ() { MagFilter = GXTexFilter.GX_LINEAR, Flags = TOBJ_FLAGS.COORD_UV | TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE, HScale = 1, WScale = 1, WrapS = GXWrapMode.CLAMP, WrapT = GXWrapMode.CLAMP, SX = 1, SY = 1, SZ = 1, GXTexGenSrc = 4, Blending = 1 }; InjectBitmap(filePath, TOBJ, imgFmt, tlutFmt); return(TOBJ); }
/// <summary> /// /// </summary> /// <returns></returns> public static HSD_TOBJ ToTOBJ(this Bitmap bmp, GXTexFmt texFmt, GXTlutFmt palFmt) { var tobj = new HSD_TOBJ() { MagFilter = GXTexFilter.GX_LINEAR, Flags = TOBJ_FLAGS.COORD_UV | TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE, HScale = 1, WScale = 1, WrapS = GXWrapMode.CLAMP, WrapT = GXWrapMode.CLAMP, SX = 1, SY = 1, SZ = 1, GXTexGenSrc = 4, Blending = 1 }; tobj.EncodeImageData(bmp.GetBGRAData(), bmp.Width, bmp.Height, texFmt, palFmt); return(tobj); }
/// <summary> /// /// </summary> /// <param name="b"></param> public static HSD_TOBJ BitmapToTOBJ(Bitmap bmp, GXTexFmt imgFormat, GXTlutFmt palFormat) { var TOBJ = new HSD_TOBJ() { MagFilter = GXTexFilter.GX_LINEAR, Flags = TOBJ_FLAGS.COORD_UV | TOBJ_FLAGS.LIGHTMAP_DIFFUSE | TOBJ_FLAGS.COLORMAP_MODULATE | TOBJ_FLAGS.ALPHAMAP_MODULATE, HScale = 1, WScale = 1, WrapS = GXWrapMode.CLAMP, WrapT = GXWrapMode.CLAMP, SX = 1, SY = 1, SZ = 1, GXTexGenSrc = 4, Blending = 1 }; InjectBitmap(bmp, TOBJ, imgFormat, palFormat); return(TOBJ); }
/// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> /// <returns></returns> public static byte[] Encode(byte[] rgba, int width, int height, GXTexFmt imgFormat, GXTlutFmt palFormat, out byte[] palette) { palette = null; if (typeToConverter.ContainsKey(imgFormat)) { return(typeToConverter[imgFormat].ConvertTo(rgba, width, height, null)); } switch (imgFormat) { case GXTexFmt.CI4: { var encode = EncodeC4(rgba, width, height, palFormat); palette = new byte[encode.Item2.Length * sizeof(short)]; Buffer.BlockCopy(encode.Item2, 0, palette, 0, palette.Length); return(encode.Item1); } case GXTexFmt.CI8: { var encode = EncodeC8(rgba, width, height, palFormat); palette = new byte[encode.Item2.Length * sizeof(short)]; Buffer.BlockCopy(encode.Item2, 0, palette, 0, palette.Length); return(encode.Item1); } case GXTexFmt.CI14X2: { // TODO: } break; } return(null); }
public static int GetImageSize(GXTexFmt format, int width, int height) { if (width % 4 != 0) { width += 4 - (width % 4); } //if (height % 4 != 0) // height += 4 - (height % 4); int size = width * height; switch (format) { case GXTexFmt.CI4: case GXTexFmt.I4: return(size / 2); case GXTexFmt.IA4: case GXTexFmt.I8: case GXTexFmt.CI14X2: case GXTexFmt.CMP: case GXTexFmt.CI8: return(size); case GXTexFmt.IA8: case GXTexFmt.RGB565: case GXTexFmt.RGB5A3: return(size * 2); case GXTexFmt.RGBA8: return(size * 4); default: return(size); } }
public static byte[] EncodeTPL(byte[] rgba, int width, int height, GXTexFmt format, GXTlutFmt palformat, out byte[] paletteData) { return(EncodeTPL(Shared.ByteArrayToUIntArray(rgba), width, height, format, palformat, out paletteData)); }
private static byte[] FromImage(uint[] rgba, int width, int height, GXTexFmt format) { byte[] b; return(FromImage(rgba, width, height, format, GXTlutFmt.IA8, out b)); }
/// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> /// <returns></returns> public static byte[] Decode(byte[] data, byte[] palData, int width, int height, GXTexFmt imgFormat, GXTlutFmt palFormat) { if (typeToConverter.ContainsKey(imgFormat)) { return(typeToConverter[imgFormat].ConvertFrom(data, width, height, null)); } switch (imgFormat) { case GXTexFmt.CI4: return(DecodeC4(data, (uint)width, (uint)height, palData, palFormat)); case GXTexFmt.CI8: return(DecodeC8(data, (uint)width, (uint)height, palData, palFormat)); case GXTexFmt.CI14X2: // TODO: break; } return(null); }
/// <summary> /// /// </summary> /// <param name="data"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> /// <returns></returns> public static byte[] Decode(byte[] data, int width, int height, GXTexFmt imgFormat) { return(Decode(data, null, width, height, imgFormat, GXTlutFmt.IA8)); }
public static byte[] DecodeTPL(GXTexFmt format, int width, int height, byte[] imageData) { return(DecodeTPL(format, width, height, imageData, GXTlutFmt.RGB565, 0, new byte[0])); }
/// <summary> /// /// </summary> /// <param name="tobj"></param> /// <param name="bmp"></param> /// <param name="imgFormat"></param> /// <param name="palFormat"></param> public static void InjectBitmap(Bitmap bmp, HSD_TOBJ tobj, GXTexFmt imgFormat, GXTlutFmt palFormat) { tobj.EncodeImageData(bmp.GetBGRAData(), bmp.Width, bmp.Height, imgFormat, palFormat); }
/// <summary> /// /// </summary> /// <param name="format"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="imageData"></param> /// <param name="palformat"></param> /// <param name="colorCount"></param> /// <param name="paletteData"></param> /// <returns></returns> public static byte[] DecodeTPL(GXTexFmt format, int width, int height, byte[] imageData, GXTlutFmt palformat, int colorCount, byte[] paletteData) { var paletteDataRgba = new uint[0]; if (IsPalettedFormat(format)) { paletteDataRgba = PaletteToRGBA(palformat, colorCount, paletteData); } byte[] rgba; switch (format) { case GXTexFmt.I4: rgba = fromI4(imageData, width, height); break; case GXTexFmt.I8: rgba = fromI8(imageData, width, height); break; case GXTexFmt.IA4: rgba = fromIA4(imageData, width, height); break; case GXTexFmt.IA8: rgba = fromIA8(imageData, width, height); break; case GXTexFmt.RGB565: rgba = fromRGB565(imageData, width, height); break; case GXTexFmt.RGB5A3: rgba = fromRGB5A3(imageData, width, height); break; case GXTexFmt.RGBA8: rgba = fromRGBA8(imageData, width, height); break; case GXTexFmt.CI4: rgba = new byte[0]; rgba = fromCI4(imageData, paletteDataRgba, width, height); break; case GXTexFmt.CI8: rgba = new byte[0]; rgba = fromCI8(imageData, paletteDataRgba, width, height); break; case GXTexFmt.CI14X2: rgba = new byte[0]; rgba = fromCI14X2(imageData, paletteDataRgba, width, height); break; case GXTexFmt.CMP: rgba = fromCMP(imageData, width, height); break; default: rgba = new byte[0]; break; } return(rgba); }
/// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void buttonAdd_Click(object sender, EventArgs e) { //if (textureList.SelectedIndices == null || textureList.SelectedIndices.Count == 0) // return; //var index = textureList.SelectedIndices[0]; var tobjs = GetTOBJs(); HSD_TOBJ tobj; var f = Tools.FileIO.OpenFiles(ApplicationSettings.ImageFileFilter); if (f != null) { GXTexFmt texFormat = GXTexFmt.CMP; GXTlutFmt palFormat = GXTlutFmt.IA8; if (tobjs.Length == 0 || tobjs[0].ImageData == null) { using (TextureImportDialog settings = new TextureImportDialog()) { if (settings.ShowDialog() == DialogResult.OK) { texFormat = settings.TextureFormat; palFormat = settings.PaletteFormat; tobjs = new HSD_TOBJ[f.Length]; int ti = 0; foreach (var fi in f) { tobj = new HSD_TOBJ(); TOBJConverter.InjectBitmap(fi, tobj, texFormat, palFormat); tobjs[ti++] = tobj; } } else { return; } } } else { texFormat = tobjs[0].ImageData.Format; if (tobjs[0].TlutData != null) { palFormat = tobjs[0].TlutData.Format; } foreach (var fi in f) { tobj = new HSD_TOBJ(); TOBJConverter.InjectBitmap(fi, tobj, texFormat, palFormat); /*if (tobj.ImageData.Width != tobjs[0].ImageData.Width || tobj.ImageData.Height != tobjs[0].ImageData.Height) * { * MessageBox.Show($"Error the texture size does not match\n{tobj.ImageData.Width}x{tobj.ImageData.Height} -> {tobjs[0].ImageData.Width}x{tobjs[0].ImageData.Height}"); * return; * }*/ tobjs = InsertAt(tobjs, tobj, tobjs.Length); } } } else { return; } SetTOBJs(tobjs); ReloadTextures(); }