public static Bitmap DecodeBitm(
byte[] bitmBytes,
int height,
int width,
int depth,
int bitsPerPixel,
BitmapType type,
BitmapFormat format,
bool swizzle,
Map map,
int visualchunkindex,
int ident)
{
int stride = 0;
#region Volume Textures / 3D
if (type == BitmapType.BITM_TYPE_3D)
{
List<Bitmap> images = new List<Bitmap>();
Bitmap finalImage = null;
List<IntPtr> tPtr = new List<IntPtr>();
if (swizzle)
{
bitmBytes = Swizzler.Swizzle(bitmBytes, width, height, depth, bitsPerPixel, true);
}
try
{
// Make our new image large enough to handle a square of all the images together with a 2 pixel pad between
int imageSize = width * height * bitsPerPixel >> 3;
int rCount = (int)(Math.Sqrt(depth) + 0.5);
int tWidth = rCount * (width + 1);
int tHeight = (int)Math.Round(depth / rCount + 0.5f, MidpointRounding.AwayFromZero) * (height + 2);
// Display 3D bitmaps combined as a 2D bitmap
if (visualchunkindex == 0)
{
for (int i = 0; i < depth; i++)
{
byte[] tempBytes = new byte[imageSize];
Array.Copy(bitmBytes, i * imageSize, tempBytes, 0, imageSize);
stride = DecodeBitmap(
ref tempBytes,
height,
width,
1,
bitsPerPixel,
type,
format,
false,
map,
visualchunkindex,
ident);
tPtr.Add(Marshal.AllocHGlobal(tempBytes.Length));
RtlMoveMemory(tPtr[tPtr.Count - 1], tempBytes, tempBytes.Length);
Bitmap bitmap = new Bitmap(
width, height, stride, PixelFormat.Format32bppArgb, tPtr[tPtr.Count - 1]);
images.Add(bitmap);
}
}
// Display only one of the 3D images
else
{
byte[] tempBytes = new byte[imageSize];
Array.Copy(bitmBytes, (visualchunkindex - 1) * imageSize, tempBytes, 0, imageSize);
stride = DecodeBitmap(
ref tempBytes,
height,
width,
1,
bitsPerPixel,
type,
format,
false,
map,
visualchunkindex,
ident);
tPtr.Add(Marshal.AllocHGlobal(tempBytes.Length));
RtlMoveMemory(tPtr[tPtr.Count - 1], tempBytes, tempBytes.Length);
images.Add(new Bitmap(width, height, stride, PixelFormat.Format32bppArgb, tPtr[tPtr.Count - 1]));
tWidth = width;
tHeight = height;
}
// create a bitmap to hold the combined image
finalImage = new Bitmap(tWidth, tHeight);
// get a graphics object from the image so we can draw on it
using (Graphics g = Graphics.FromImage(finalImage))
{
// set background color
g.Clear(Color.Empty);
// go through each image and draw it on the final image
int offset = 0;
foreach (Bitmap image in images)
{
g.DrawImage(
image,
new Rectangle(
offset % tWidth, (offset / tWidth) * (image.Height + 1), image.Width, image.Height));
offset += image.Width + 1;
}
}
return finalImage;
}
catch (Exception ex)
{
if (finalImage != null)
{
finalImage.Dispose();
}
throw ex;
//Global.ShowErrorMsg("Error loading bitmap", ex);
}
finally
{
// clean up memory
foreach (Bitmap image in images)
{
image.Dispose();
}
foreach (IntPtr p in tPtr)
{
Marshal.FreeHGlobal(p);
}
}
}
#endregion
#region Cubemap
else if (type == BitmapType.BITM_TYPE_CUBEMAP)
{
// stride = DecodeBitmap(ref bitmBytes, height, width, 1, bitsPerPixel, type, format, swizzle, map, visualchunkindex, ident);
List<Bitmap> images = new List<Bitmap>();
Bitmap finalImage = null;
List<IntPtr> tPtr = new List<IntPtr>();
// Don't think any cubemaps are swizzled, but...
if (swizzle)
{
int imageSize = bitmBytes.Length / 6; // width * height * bitsPerPixel >> 3;
for (int i = 0; i < 6; i++)
{
bitmBytes = Swizzler.Swizzle(bitmBytes, i * imageSize, width, height, depth, bitsPerPixel, true);
}
}
try
{
// Make our new image large enough to handle a square of all the images together with a 2 pixel pad between
//int tWidth = 2 * (width + 2) + 10; // Add some extras..
int tWidth = 4 * width; // Add some extras..
int tHeight = 3 * height;
int imageSize = width * height * (bitsPerPixel >> 3);
// Total image size has each image (including it's mipmaps) padded to 256
int tImageSize = bitmBytes.Length / 6;
// Unused, just divide stream size by 6 as above
int ttImageSize = imageSize +
((imageSize / 6) % 256 == 0 ? 0 : ((256 * 6) - (imageSize % (256 * 6))));
// All cubemaps should be DXT1...
switch (format)
{
case BitmapFormat.BITM_FORMAT_DXT1:
imageSize = Math.Max(imageSize / 8, 8);
break;
case BitmapFormat.BITM_FORMAT_DXT2AND3:
case BitmapFormat.BITM_FORMAT_DXT4AND5:
imageSize = Math.Max(imageSize / 4, 16);
break;
}
//int mipmaps = 0;
for (int i = 0; i < 6; i++)
{
int tw = width;
int th = height;
int tempSize = imageSize;
int offset = 0;
//while (tw > 2 & th > 2)
{
byte[] tempBytes = new byte[tempSize];
Array.Copy(bitmBytes, i * tImageSize + offset, tempBytes, 0, tempSize);
stride = DecodeBitmap(
ref tempBytes,
th,
tw,
1,
bitsPerPixel,
type,
format,
false,
map,
visualchunkindex,
ident);
tPtr.Add(Marshal.AllocHGlobal(tempBytes.Length));
RtlMoveMemory(tPtr[tPtr.Count - 1], tempBytes, tempBytes.Length);
Bitmap bitmap = new Bitmap(
tw, th, stride, PixelFormat.Format32bppArgb, tPtr[tPtr.Count - 1]);
images.Add(bitmap);
offset += tempSize;
tempSize /= 4;
tw /= 2;
th /= 2;
}
}
// create a bitmap to hold the combined image
finalImage = new Bitmap(tWidth, tHeight);
// get a graphics object from the image so we can draw on it
using (Graphics g = Graphics.FromImage(finalImage))
{
// set background color
g.Clear(Color.Empty);
//
int[] crossX = new int[6] { 2, 0, 1, 1, 1, 3 }; // Right, Left, Top, Bottom, Front, Back
int[] crossY = new int[6] { 1, 1, 0, 2, 1, 1 }; // Right, Left, Top, Bottom, Front, Back
// go through each image and draw it on the final image
int xOffset = 0;
int yOffset = 0;
int tempCount = 0;
foreach (Bitmap image in images)
{
/*
if (mipmapCount == 0)
{
xOffset = 0;
yOffset += image.Height + 2;
mipmapCount = images.Count / 6;
}
*/
xOffset = crossX[tempCount] * image.Width;
yOffset = crossY[tempCount] * image.Height;
g.DrawImage(image, new Rectangle(xOffset, yOffset, image.Width, image.Height));
tempCount++;
}
}
return finalImage;
}
catch (Exception ex)
{
if (finalImage != null)
{
finalImage.Dispose();
}
throw ex;
//Global.ShowErrorMsg("Error while processing bitmap", ex);
}
finally
{
// clean up memory
foreach (Bitmap image in images)
{
image.Dispose();
}
foreach (IntPtr p in tPtr)
{
Marshal.FreeHGlobal(p);
}
}
}
#endregion
#region 2D Textures
else
{
stride = DecodeBitmap(
ref bitmBytes, height, width, 1, bitsPerPixel, type, format, swizzle, map, visualchunkindex, ident);
}
#endregion
/*
// This creates a memory leaks from HGlobal
IntPtr intPtr = Marshal.AllocHGlobal(bitmBytes.Length);
RtlMoveMemory(intPtr, bitmBytes, bitmBytes.Length);
Bitmap temp = new Bitmap(width, height, stride, PixelFormat.Format32bppArgb, intPtr);
temp.Tag = intPtr; // This NEEDS to be released when disposed
*/
Bitmap temp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Rectangle rect = new Rectangle( 0, 0, width, height);
BitmapData data = null;
try
{
data = temp.LockBits(rect, ImageLockMode.WriteOnly, temp.PixelFormat);
System.Runtime.InteropServices.Marshal.Copy(bitmBytes, 0, data.Scan0, Math.Min(bitmBytes.Length, data.Width * data.Height * 4));
}
finally
{
if (data != null)
temp.UnlockBits(data);
}
return temp;
}