private static Bitmap DownscaleTwoThirds(Bitmap img) { if (((img.Width * 2) % 3) != 0 || ((img.Height * 2) % 3) != 0) { throw new Exception("Cannot cleanly two-thirds scale image!"); } return(FontProcessing.DownscaleInteger(FontProcessing.PointScale(img, 2), 3)); }
private static Bitmap DoKaruta13(Bitmap wtex, Bitmap utex) { // this is very messy but the dimensions just don't match between versions // we should probably just inject a differently sized texture instead, really... Bitmap cropped1 = FontProcessing.Crop(utex, 10, 4, utex.Width - 24, utex.Height - 5); Bitmap upscaled = FontProcessing.PointScale(cropped1, 6); Bitmap cropped2 = FontProcessing.Crop(upscaled, 0, 1, upscaled.Width, upscaled.Height - 1); Bitmap downscaled = FontProcessing.DownscaleInteger(cropped2, 11); return(DoCropExpandCanvas(downscaled, (uint)wtex.Width, (uint)wtex.Height)); }
private static Bitmap DoKarutaHalfAndHalf(Bitmap wtex, Bitmap utex, uint wx, uint ux, uint uw) { Bitmap left = FontProcessing.Crop(wtex, 0, 0, (int)wx, wtex.Height); Bitmap right = DownscaleTwoThirds(FontProcessing.Crop(utex, (int)ux, 0, (int)uw, utex.Height)); long diff = wtex.Width - (left.Width + right.Width); if (diff > 0) { Bitmap mid = new Bitmap((int)diff, wtex.Height); for (int y = 0; y < mid.Height; ++y) { for (int x = 0; x < mid.Width; ++x) { mid.SetPixel(x, y, Color.FromArgb(0, 0, 0, 0)); } } left = StitchHorizontal(left, mid); } return(StitchHorizontal(left, right)); }
public static Stream ProcessTexture(string name, DuplicatableStream ustream, DuplicatableStream wstream) { FPS4 w = new FPS4(wstream.Duplicate()); TXM wtxm = new TXM(w.GetChildByIndex(0).AsFile.DataStream.Duplicate()); TXV wtxv = new TXV(wtxm, w.GetChildByIndex(1).AsFile.DataStream.Duplicate(), false); FPS4 u = new FPS4(ustream.Duplicate()); TXM utxm = new TXM(u.GetChildByIndex(0).AsFile.DataStream.Duplicate()); TXV utxv = new TXV(utxm, u.GetChildByIndex(1).AsFile.DataStream.Duplicate(), false); List <TexConvRules> convs = new List <TexConvRules>(); if (name == "rootR.cpk/mg/tex/karuta.tex") { convs.Add(new TexConvRules() { WTexId = 2, UTexId = 1, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKarutaHalfAndHalf(wtex, utex, 82, 134, 294) }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 3, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKarutaHalfAndHalf(wtex, utex, 86, 134, 294) }); convs.Add(new TexConvRules() { WTexId = 7, UTexId = 7, Method = TexConvMethod.DownscaleTwoThirds }); convs.Add(new TexConvRules() { WTexId = 13, UTexId = 13, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DoKaruta13(wtex, utex) }); convs.Add(new TexConvRules() { WTexId = 17, UTexId = 17, Method = TexConvMethod.DownscaleTwoThirds }); convs.Add(new TexConvRules() { WTexId = 22, UTexId = 23, Method = TexConvMethod.Delegate, Delegate = (wtex, utex) => DownscaleTwoThirds(CropExpandCanvas(utex, 2, -2, (uint)(utex.Width + 3), (uint)(utex.Height - 3))) }); } else if (name == "rootR.cpk/mnu/tex/main.tex") { convs.Add(new TexConvRules() { WTexId = 110, UTexId = 61, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 111, UTexId = 62, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 112, UTexId = 63, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 113, UTexId = 64, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 114, UTexId = 65, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 115, UTexId = 66, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 116, UTexId = 67, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 117, UTexId = 68, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 118, UTexId = 69, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 119, UTexId = 70, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 124, UTexId = 75, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/mnu/tex/shop.tex") { convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 2, UTexId = 2, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 3, UTexId = 3, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 4, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 5, UTexId = 5, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 6, UTexId = 6, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 7, UTexId = 7, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/mnu/tex/skill.tex") { convs.Add(new TexConvRules() { WTexId = 0, UTexId = 0, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 2, UTexId = 2, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 3, UTexId = 3, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 4, Method = TexConvMethod.Downscale2x }); convs.Add(new TexConvRules() { WTexId = 5, UTexId = 5, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/mnu/tex/snd_test.tex") { convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Downscale2x }); } else if (name == "rootR.cpk/SysSub/JA/TitleTexture.tex") { convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 2, UTexId = 4, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 3, UTexId = 6, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 4, UTexId = 8, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 6, UTexId = 12, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 7, UTexId = 14, Method = TexConvMethod.CropExpandCanvas }); convs.Add(new TexConvRules() { WTexId = 8, UTexId = 16, Method = TexConvMethod.CropExpandCanvas }); } else if (name.EndsWith(".CLG")) { convs.Add(new TexConvRules() { WTexId = 0, UTexId = 0, Method = TexConvMethod.DownscaleTwoThirds }); convs.Add(new TexConvRules() { WTexId = 1, UTexId = 1, Method = TexConvMethod.Clear }); } MemoryStream s = wstream.Duplicate().CopyToMemory(); s.Position = 0; foreach (TexConvRules c in convs) { var wm = wtxm.TXMRegulars[c.WTexId]; var um = utxm.TXMRegulars[c.UTexId]; var wv = wtxv.textures.Where(x => x.TXM == wm).First(); var uv = utxv.textures.Where(x => x.TXM == um).First(); System.Drawing.Bitmap newImage = null; switch (c.Method) { case TexConvMethod.Downscale2x: { newImage = FontProcessing.DownscaleInteger(uv.GetBitmaps()[0], 2); } break; case TexConvMethod.DownscaleTwoThirds: { newImage = DownscaleTwoThirds(uv.GetBitmaps()[0]); } break; case TexConvMethod.CropExpandCanvas: { newImage = DoCropExpandCanvas(uv.GetBitmaps()[0], wm.Width, wm.Height); } break; case TexConvMethod.Clear: { newImage = new Bitmap(wv.GetBitmaps()[0]); for (int y = 0; y < newImage.Height; ++y) { for (int x = 0; x < newImage.Width; ++x) { newImage.SetPixel(x, y, Color.FromArgb(0, 0, 0, 0)); } } } break; case TexConvMethod.Delegate: { newImage = c.Delegate(wv.GetBitmaps()[0], uv.GetBitmaps()[0]); } break; default: { throw new Exception("don't know how to convert " + uv.TXM.Name); } } if (newImage != null) { HyoutaTools.Util.Assert(newImage.Width == wm.Width); HyoutaTools.Util.Assert(newImage.Height == wm.Height); if (wm.Format == HyoutaTools.Tales.Vesperia.Texture.TextureFormat.Indexed8Bits_RGB5A3) { ChopBitsRGB5A3(newImage); var palette = GeneratePalette256(newImage); s.Position = w.Files[1].Location.Value + wm.TxvLocation; foreach (var loc in new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(newImage.Width, newImage.Height, 8, 4)) { int cval = 0; if (loc.X < newImage.Width && loc.Y < newImage.Height) { cval = palette.lookup[newImage.GetPixel(loc.X, loc.Y)]; } s.WriteByte((byte)cval); } for (int ci = 0; ci < 256; ++ci) { ushort cval = 0; if (ci < palette.colors.Count) { cval = HyoutaTools.Textures.ColorFetchingIterators.ColorFetcherRGB5A3.ColorToRGB5A3(palette.colors[ci]); } s.WriteUInt16(cval.ToEndian(EndianUtils.Endianness.BigEndian)); } } else if (wm.Format == HyoutaTools.Tales.Vesperia.Texture.TextureFormat.GamecubeRGBA8) { s.Position = w.Files[1].Location.Value + wm.TxvLocation; byte[] tmpb = new byte[0x40]; int tmpp = 0; foreach (var loc in new HyoutaTools.Textures.PixelOrderIterators.TiledPixelOrderIterator(newImage.Width, newImage.Height, 4, 4)) { Color col = newImage.GetPixel(loc.X, loc.Y); tmpb[tmpp * 2 + 0] = col.A; tmpb[tmpp * 2 + 1] = col.R; tmpb[tmpp * 2 + 0 + 0x20] = col.G; tmpb[tmpp * 2 + 1 + 0x20] = col.B; ++tmpp; if (tmpp == 16) { tmpp = 0; s.Write(tmpb); } } if (tmpp != 0) { throw new Exception("Unexpected tile size for " + wm.Name); } } else { Console.WriteLine("don't know how to encode into " + wm.Format); } } } s.Position = 0; return(s); }