private static Bitmap getIMG_ETC1(BCHTexture bchtex, byte[] data)
{
Bitmap img = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16));
string dllpath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location).Replace('\\', '/') + "/ETC1.dll";
if (!File.Exists(dllpath)) File.WriteAllBytes(dllpath, Resources.ETC1);
try
{
/*
* Much of this code is taken/modified from Tharsis: http://jul.rustedlogic.net/thread.php?pid=436556#436556 Thank you to Tharsis's creator, xdaniel.
*/
byte[] temp = new byte[bchtex.Length];
Array.Copy(data, bchtex.DataOffset, temp, 0, bchtex.Length);
/* Get compressed data & handle to it */
byte[] textureData = temp;
//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, size2 = 0;
UInt16 wd = (ushort)img.Width, ht = (ushort)img.Height;
ConvertETC1(IntPtr.Zero, ref size1, IntPtr.Zero, ref size2, wd, ht, bchtex.Format == 0xD || bchtex.Format == 0xB); //true = etc1a4, false = etc1
uint[] output = new uint[size1];
GCHandle pOutput = GCHandle.Alloc(output, GCHandleType.Pinned);
ConvertETC1(pOutput.AddrOfPinnedObject(), ref size1, pInput.AddrOfPinnedObject(), ref size2, wd, ht, bchtex.Format == 0xD || bchtex.Format == 0xB);
pOutput.Free();
pInput.Free();
/* Unscramble if needed // could probably be done in ETC1.dll, it's probably pretty damn 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);
int h = img.Height;
int w = img.Width;
byte[] imgData = tmp;
for (int i = 0; i < img.Width; i++)
{
for (int j = 0; j < img.Height; j++)
{
int k = (j + i * img.Height) * 4;
Color c = Color.FromArgb(imgData[k + 3], imgData[k], imgData[k + 1], imgData[k + 2]);
if (imgData[k] == imgData[k + 1] && imgData[k + 1] == imgData[k + 2] && imgData[k + 1] == 0)
{
if (imgData[k + 3] == 0)
{
c = Color.Transparent;
}
}
img.SetPixel(i, j, c);
/*if (bchtex.Format == 0xD)
{
img.SetPixel(i, j, Color.FromArgb(0xFF, imgData[k], imgData[k + 1], imgData[k + 2]));
}*/
}
}
//image is 13 instead of 12
// 24 34
img.RotateFlip(RotateFlipType.Rotate90FlipX);
if (wd > ht)
{
//image is now in appropriate order, but the shifting done been fucked up. Let's fix that.
Bitmap img2 = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16));
for (int y = 0; y < Math.Max(nlpo2(bchtex.Width), 16); y += 8)
{
for (int x = 0; x < Math.Max(nlpo2(bchtex.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
}
}
}
return img2;
}
else if (ht > wd)
{
//image is now in appropriate order, but the shifting done been fucked up. Let's fix that.
Bitmap img2 = new Bitmap(Math.Max(nlpo2(bchtex.Width), 16), Math.Max(nlpo2(bchtex.Height), 16));
for (int y = 0; y < Math.Max(nlpo2(bchtex.Width), 16); y += 8)
{
for (int x = 0; x < Math.Max(nlpo2(bchtex.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
}
}
}
return img2;
}
}
catch (IndexOutOfRangeException)
{
//
}
catch (AccessViolationException)
{
//
}
return img;
}