diff --git a/pk3DS/3DS/BCLIM.cs b/pk3DS/3DS/BCLIM.cs index 8f79cde..e6605b3 100644 --- a/pk3DS/3DS/BCLIM.cs +++ b/pk3DS/3DS/BCLIM.cs @@ -2,6 +2,8 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; +using System.Runtime.InteropServices; +using pk3DS.Properties; // For other projects, replace this line with the namespace that contains your ETC1Lib.dll resource. namespace CTR { @@ -97,7 +99,7 @@ internal static Image makeBMP(string path, bool autosave = false, bool crop = tr else img = getIMG(bclim); - if (img == null) return img; + if (img == null) return null; Rectangle cropRect = new Rectangle(0, 0, bclim.Width, bclim.Height); Bitmap CropBMP = new Bitmap(cropRect.Width, cropRect.Height); using (Graphics g = Graphics.FromImage(CropBMP)) @@ -235,22 +237,99 @@ internal static Bitmap getIMG_XY7(CLIM bclim) } internal static Bitmap getIMG_ETC(CLIM bclim) { - //int format = bclim.FileFormat; - //if (format != 10 && format != 11) - // return null; + Bitmap img = new Bitmap(Math.Max(nlpo2(bclim.Width), 16), Math.Max(nlpo2(bclim.Height), 16)); + string dllpath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\ETC1Lib.dll"; + if (!File.Exists(dllpath)) File.WriteAllBytes(dllpath, Resources.ETC1Lib); - //byte[] data = ETC1_Decompress(bclim.Data, bclim.Width, bclim.Height, format + 2); - //Bitmap img = new Bitmap(bclim.Width, bclim.Height); + try + { + /* http://jul.rustedlogic.net/thread.php?id=17312 + * Much of this code is taken/modified from Tharsis. Thank you to Tharsis's creator, xdaniel. + * https://github.com/xdanieldzd/Tharsis + */ - //for (int i = 0; i < bclim.Width * bclim.Height; i++) // for every pixel - //{ - // Color c = DecodeColor(BitConverter.ToUInt32(data, i * 4), 9); - // int x = i % bclim.Width; - // int y = i / bclim.Width; - // img.SetPixel(x, y, c); - //} - //return img; - return null; + /* Get compressed data & handle to it */ + byte[] textureData = bclim.Data; + //textureData = switchEndianness(textureData, 0x10); + ushort[] input = new ushort[textureData.Length/sizeof (ushort)]; + Buffer.BlockCopy(textureData, 0, input, 0, textureData.Length); + GCHandle pInput = GCHandle.Alloc(input, GCHandleType.Pinned); + + /* Marshal data around, invoke ETC1.dll for conversion, etc */ + UInt32 size1 = 0; + UInt16 w = (ushort)img.Width, h = (ushort)img.Height; + + ETC1.ConvertETC1(IntPtr.Zero, ref size1, IntPtr.Zero, w, h, bclim.FileFormat == 0xB); // true = etc1a4, false = etc1 + // System.Diagnostics.Debug.WriteLine(size1); + uint[] output = new uint[size1]; + GCHandle pOutput = GCHandle.Alloc(output, GCHandleType.Pinned); + ETC1.ConvertETC1(pOutput.AddrOfPinnedObject(), ref size1, pInput.AddrOfPinnedObject(), w, h, bclim.FileFormat == 0xB); + pOutput.Free(); + pInput.Free(); + + + /* Unscramble if needed // could probably be done in ETC1Lib.dll, it's probably pretty ugly, but whatever... */ + /* Non-square code blocks could need some cleanup, verification, etc. as well... */ + uint[] finalized = new uint[output.Length]; + + // Act if it's square because BCLIM swizzling is stupid + Buffer.BlockCopy(output, 0, finalized, 0, finalized.Length); + + byte[] tmp = new byte[finalized.Length]; + Buffer.BlockCopy(finalized, 0, tmp, 0, tmp.Length); + byte[] imgData = tmp; + + for (int i = 0; i < w; i++) + { + for (int j = 0; j < h; j++) + { + int k = (j + i*img.Height)*4; + img.SetPixel(i, j, Color.FromArgb(imgData[k + 3], imgData[k], imgData[k + 1], imgData[k + 2])); + } + } + // Image is 13 instead of 12 + // 24 34 + img.RotateFlip(RotateFlipType.Rotate90FlipX); + if (w > h) + { + // Image is now in appropriate order, but the shifting is messed up. Let's fix that. + Bitmap img2 = new Bitmap(Math.Max(nlpo2(bclim.Width), 16), Math.Max(nlpo2(bclim.Height), 16)); + for (int y = 0; y < Math.Max(nlpo2(bclim.Width), 16); y += 8) + { + for (int x = 0; x < Math.Max(nlpo2(bclim.Height), 16); x++) + { + for (int j = 0; j < 8; j++) + // Treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. + { + int x1 = (x + ((y/8)*h))%img2.Width; // Reshift x + int y1 = ((x + ((y/8)*h))/img2.Width)*8; // Reshift y + img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); // Reswizzle + } + } + } + img = img2; + } + else if (h > w) + { + Bitmap img2 = new Bitmap(Math.Max(nlpo2(bclim.Width), 16), Math.Max(nlpo2(bclim.Height), 16)); + for (int y = 0; y < Math.Max(nlpo2(bclim.Width), 16); y += 8) + { + for (int x = 0; x < Math.Max(nlpo2(bclim.Height), 16); x++) + { + for (int j = 0; j < 8; j++) + // Treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. + { + int x1 = x%img2.Width; // Reshift x + int y1 = ((x + ((y/8)*h))/img2.Width)*8; // Reshift y + img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); // Reswizzle + } + } + } + img = img2; + } + } + catch { } + return img; } // BCLIM Data Writing diff --git a/pk3DS/3DS/ETC1.cs b/pk3DS/3DS/ETC1.cs index f269887..d78b93b 100644 --- a/pk3DS/3DS/ETC1.cs +++ b/pk3DS/3DS/ETC1.cs @@ -1,6 +1,11 @@ -namespace CTR +using System; +using System.Runtime.InteropServices; + +namespace CTR { class ETC1 { + [DllImport("ETC1Lib.dll", EntryPoint = "ConvertETC1", CallingConvention = CallingConvention.Cdecl)] + public static extern void ConvertETC1(IntPtr dataOut, ref UInt32 dataOutSize, IntPtr dataIn, UInt16 width, UInt16 height, bool alpha); } -} +} \ No newline at end of file diff --git a/pk3DS/Properties/Resources.Designer.cs b/pk3DS/Properties/Resources.Designer.cs index fd7e2bb..18d273d 100644 --- a/pk3DS/Properties/Resources.Designer.cs +++ b/pk3DS/Properties/Resources.Designer.cs @@ -10470,6 +10470,16 @@ internal class Resources { } } + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ETC1Lib { + get { + object obj = ResourceManager.GetObject("ETC1Lib", resourceCulture); + return ((byte[])(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/pk3DS/Properties/Resources.resx b/pk3DS/Properties/Resources.resx index 0d9c780..fd64127 100644 --- a/pk3DS/Properties/Resources.resx +++ b/pk3DS/Properties/Resources.resx @@ -4519,4 +4519,7 @@ ..\Resources\romdata\txt\3dsgames.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + ..\Resources\ETC1Lib.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/pk3DS/Resources/ETC1Lib.dll b/pk3DS/Resources/ETC1Lib.dll new file mode 100644 index 0000000..81bf863 Binary files /dev/null and b/pk3DS/Resources/ETC1Lib.dll differ diff --git a/pk3DS/pk3DS.csproj b/pk3DS/pk3DS.csproj index 9ca3c09..f5137c0 100644 --- a/pk3DS/pk3DS.csproj +++ b/pk3DS/pk3DS.csproj @@ -4677,6 +4677,9 @@ + + +