599 lines
24 KiB
C#
599 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace SM64Lib.N64Graphics
|
|
{
|
|
public class TextureFormats
|
|
{
|
|
public static Bitmap createColorTexture(Color color)
|
|
{
|
|
Bitmap tex = new Bitmap(1, 1);
|
|
Graphics.FromImage(tex).Clear(color);
|
|
return tex;
|
|
}
|
|
|
|
public static string ConvertFormatToString(byte formatColorType, byte formatByteSize)
|
|
{
|
|
string formatStr = "";
|
|
switch (formatColorType & 7)
|
|
{
|
|
case 0: formatStr = "RGBA"; break;
|
|
case 1: formatStr = "YUV"; break;
|
|
case 2: formatStr = "CI"; break;
|
|
case 3: formatStr = "IA"; break;
|
|
case 4: formatStr = "I"; break;
|
|
default: formatStr = "UNKNOWN"; break;
|
|
}
|
|
switch (formatByteSize & 3)
|
|
{
|
|
case 0: formatStr += "4"; break;
|
|
case 1: formatStr += "8"; break;
|
|
case 2: formatStr += "16"; break;
|
|
case 3: formatStr += "32"; break;
|
|
}
|
|
return formatStr;
|
|
}
|
|
|
|
public static byte ConvertStringToFormat(string str)
|
|
{
|
|
str = str.ToLower();
|
|
if (str.Equals("rgba16"))
|
|
return 0x10;
|
|
else if (str.Equals("rgba32"))
|
|
return 0x18;
|
|
else if (str.Equals("ci4"))
|
|
return 0x40;
|
|
else if (str.Equals("ci8"))
|
|
return 0x48;
|
|
else if (str.Equals("ia4"))
|
|
return 0x60;
|
|
else if (str.Equals("ia8"))
|
|
return 0x68;
|
|
else if (str.Equals("ia16"))
|
|
return 0x70;
|
|
else if (str.Equals("i4"))
|
|
return 0x80;
|
|
else if (str.Equals("i8"))
|
|
return 0x88;
|
|
else if (str.Equals("1bpp")) // Not a real F3D format.
|
|
return 0x00;
|
|
|
|
return 0x10;
|
|
}
|
|
|
|
public static int getNumberOfBitsForFormat(byte format)
|
|
{
|
|
switch (format)
|
|
{
|
|
case 0x00: // Note: "1 bit per pixel" is not a Fast3D format.
|
|
return 1;
|
|
case 0x40:
|
|
case 0x60:
|
|
case 0x80:
|
|
return 4;
|
|
case 0x48:
|
|
case 0x68:
|
|
case 0x88:
|
|
return 8;
|
|
case 0x10:
|
|
case 0x70:
|
|
case 0x90:
|
|
default:
|
|
return 16;
|
|
case 0x18:
|
|
return 32;
|
|
}
|
|
}
|
|
|
|
public static byte[] encodeTexture(N64Codec format, Bitmap texture)
|
|
{
|
|
switch (format)
|
|
{
|
|
default:
|
|
case N64Codec.ONEBPP: // Note: "1 bit per pixel" is not a Fast3D format.
|
|
return encode1BPP(texture);
|
|
case N64Codec.RGBA16:
|
|
return encodeRGBA16(texture);
|
|
case N64Codec.RGBA32:
|
|
return encodeRGBA32(texture);
|
|
case N64Codec.IA4:
|
|
return encodeIA4(texture);
|
|
case N64Codec.IA8:
|
|
return encodeIA8(texture);
|
|
case N64Codec.IA16:
|
|
return encodeIA16(texture);
|
|
case N64Codec.I4:
|
|
return encodeI4(texture);
|
|
case N64Codec.I8:
|
|
return encodeI4(texture);
|
|
case N64Codec.CI4:
|
|
case N64Codec.CI8:
|
|
throw new ArgumentException("CI texture encoding is not currently supported in this version.");
|
|
}
|
|
}
|
|
|
|
public static byte getBit(int color, int bit)
|
|
{
|
|
return (byte)(((color >> 24) & 0xFF) > 0 ? (1 << bit) : 0);
|
|
}
|
|
|
|
public static byte[] encode1BPP(Bitmap texture)
|
|
{
|
|
int data_size = (texture.Width * texture.Height) / 8;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size; i++)
|
|
{
|
|
int x = (i * 8) % texture.Width;
|
|
int y = (i * 8) / texture.Width;
|
|
|
|
data[i] = (byte)(
|
|
getBit(texture.GetPixel(x + 0, y).ToArgb(), 7) |
|
|
getBit(texture.GetPixel(x + 1, y).ToArgb(), 6) |
|
|
getBit(texture.GetPixel(x + 2, y).ToArgb(), 5) |
|
|
getBit(texture.GetPixel(x + 3, y).ToArgb(), 4) |
|
|
getBit(texture.GetPixel(x + 4, y).ToArgb(), 3) |
|
|
getBit(texture.GetPixel(x + 5, y).ToArgb(), 2) |
|
|
getBit(texture.GetPixel(x + 6, y).ToArgb(), 1) |
|
|
getBit(texture.GetPixel(x + 7, y).ToArgb(), 0)
|
|
);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static byte[] encodeRGBA16(Bitmap texture)
|
|
{
|
|
int data_size = (texture.Width * texture.Height) * 2;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size / 2; i++)
|
|
{
|
|
int x = i % texture.Width;
|
|
int y = i / texture.Width;
|
|
Color pix = texture.GetPixel(x, y);
|
|
byte red = (byte)((pix.R / 256.0f) * 32.0f);
|
|
byte green = (byte)((pix.G / 256.0f) * 32.0f);
|
|
byte blue = (byte)((pix.B / 256.0f) * 32.0f);
|
|
byte alpha = (byte)(pix.A >= 128.0f ? 1 : 0);
|
|
|
|
data[i * 2] = (byte)((red << 3) | (green >> 2));
|
|
data[(i * 2) + 1] = (byte)(((green & 3) << 6) | (blue << 1) | alpha);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static byte[] encodeRGBA32(Bitmap texture)
|
|
{
|
|
int data_size = (texture.Width * texture.Height) * 4;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size / 4; i++)
|
|
{
|
|
int x = i % texture.Width;
|
|
int y = i / texture.Width;
|
|
Color pix = texture.GetPixel(x, y);
|
|
|
|
data[(i * 4) + 0] = pix.R;
|
|
data[(i * 4) + 1] = pix.G;
|
|
data[(i * 4) + 2] = pix.B;
|
|
data[(i * 4) + 3] = pix.A;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static byte[] encodeIA4(Bitmap texture)
|
|
{
|
|
int data_size = (texture.Width * texture.Height) / 2;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size; i++)
|
|
{
|
|
int x = (i * 2) % texture.Width;
|
|
int y = (i * 2) / texture.Width;
|
|
|
|
Color pix1 = texture.GetPixel(x, y);
|
|
byte pix1_avg = (byte)((((pix1.R + pix1.G + pix1.B) / 3) / 255.0f) * 8.0f);
|
|
byte upper = (byte)((pix1_avg << 1) | (pix1.A < 255 ? 0 : 1));
|
|
|
|
Color pix2 = texture.GetPixel(x + 1, y);
|
|
byte pix2_avg = (byte)((((pix2.R + pix2.G + pix2.B) / 3) / 255.0f) * 8.0f);
|
|
byte lower = (byte)((pix2_avg << 1) | (pix2.A < 255 ? 0 : 1));
|
|
|
|
data[i] = (byte)(((upper & 0xF) << 4) | (lower & 0xF));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static byte[] encodeIA8(Bitmap texture)
|
|
{
|
|
int data_size = texture.Width * texture.Height;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size; i++)
|
|
{
|
|
int x = i % texture.Width;
|
|
int y = i / texture.Width;
|
|
|
|
Color pix = texture.GetPixel(x, y);
|
|
byte pix_avg = (byte)((((pix.R + pix.G + pix.B) / 3) / 255.0f) * 16.0f);
|
|
byte pix_alpha = (byte)((pix.A / 255.0f) * 16.0f);
|
|
|
|
data[i] = (byte)(((pix_avg & 0xF) << 4) | (pix_alpha & 0xF));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static byte[] encodeIA16(Bitmap texture)
|
|
{
|
|
int data_size = texture.Width * texture.Height * 2;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size / 2; i++)
|
|
{
|
|
int x = i % texture.Width;
|
|
int y = i / texture.Width;
|
|
|
|
Color pix = texture.GetPixel(x, y);
|
|
byte pix_avg = (byte)((pix.R + pix.G + pix.B) / 3);
|
|
|
|
data[i * 2] = pix_avg;
|
|
data[(i * 2) + 1] = pix.A;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static byte[] encodeI4(Bitmap texture)
|
|
{
|
|
int data_size = (texture.Width * texture.Height) / 2;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size; i++)
|
|
{
|
|
int x = (i * 2) % texture.Width;
|
|
int y = (i * 2) / texture.Width;
|
|
|
|
Color pix1 = texture.GetPixel(x, y);
|
|
byte upper = (byte)((((pix1.R + pix1.G + pix1.B) / 3) / 255.0f) * 16.0f);
|
|
|
|
Color pix2 = texture.GetPixel(x + 1, y);
|
|
byte lower = (byte)((((pix2.R + pix2.G + pix2.B) / 3) / 255.0f) * 16.0f);
|
|
|
|
data[i] = (byte)(((upper & 0xF) << 4) | (lower & 0xF));
|
|
}
|
|
return data;
|
|
}
|
|
|
|
|
|
public static byte[] encodeI8(Bitmap texture)
|
|
{
|
|
int data_size = texture.Width * texture.Height;
|
|
byte[] data = new byte[data_size];
|
|
for (int i = 0; i < data_size; i++)
|
|
{
|
|
int x = i % texture.Width;
|
|
int y = i / texture.Width;
|
|
|
|
Color pix = texture.GetPixel(x, y);
|
|
|
|
data[i] = (byte)((pix.R + pix.G + pix.B) / 3);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
public static Bitmap decodeTexture(N64Codec format, byte[] data, int width, int height, ushort[] palette)
|
|
{
|
|
switch (format)
|
|
{
|
|
default:
|
|
case N64Codec.ONEBPP: // Note: "1 bit per pixel" is not a Fast3D format.
|
|
return decode1BPP(data, width, height);
|
|
case N64Codec.RGBA16:
|
|
return decodeRGBA16(data, width, height);
|
|
case N64Codec.RGBA32:
|
|
return decodeRGBA32(data, width, height);
|
|
case N64Codec.CI4:
|
|
return decodeCI4(data, width, height, palette);
|
|
case N64Codec.CI8:
|
|
return decodeCI8(data, width, height, palette);
|
|
case N64Codec.IA4:
|
|
return decodeIA4(data, width, height);
|
|
case N64Codec.IA8:
|
|
return decodeIA8(data, width, height);
|
|
case N64Codec.IA16:
|
|
return decodeIA16(data, width, height);
|
|
case N64Codec.I4:
|
|
return decodeI4(data, width, height);
|
|
case N64Codec.I8:
|
|
return decodeI8(data, width, height);
|
|
}
|
|
}
|
|
|
|
|
|
public static Bitmap decode1BPP(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
if (data.Length >= (width * height) / 8) // Sanity Check
|
|
{
|
|
int len = (width * height) / 8;
|
|
for (int i = 0; i < len; ++i)
|
|
{
|
|
for (int x = 0; x < 8; x++)
|
|
{
|
|
byte intensity = (byte)((data[i] >> (7 - x)) & 1);
|
|
if (intensity > 0)
|
|
intensity = 0xFF;
|
|
int alpha = intensity;
|
|
int pos = (i * 8) + x;
|
|
tex.SetPixel(pos % width, pos / width, Color.FromArgb(alpha, intensity, intensity, intensity));
|
|
}
|
|
}
|
|
}
|
|
tex.Tag = new string[] { "Format: 1BPP", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
|
|
public static Bitmap decodeRGBA32(byte[] data, int width, int height)
|
|
{
|
|
Console.WriteLine("Texture size = (" + width + "x" + height + ")");
|
|
Console.WriteLine("data.Length = (" + data.Length + ")");
|
|
Bitmap tex = new Bitmap(width, height);
|
|
|
|
if (data.Length >= width * height * 4) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
|
|
int len = width * height;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
// Swap red and blue values
|
|
byte temp_red = data[(i * 4) + 0];
|
|
data[(i * 4) + 0] = data[(i * 4) + 2];
|
|
data[(i * 4) + 2] = temp_red;
|
|
}
|
|
Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
|
|
}
|
|
tex.Tag = new string[] { "Format: RGBA32", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
|
|
public static Bitmap decodeRGBA16(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
if (data.Length >= width * height * 2) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = width * height;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
ushort pixel = (ushort)((data[i * 2] << 8) | data[i * 2 + 1]);
|
|
pixels[(i * 4) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red
|
|
pixels[(i * 4) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green
|
|
pixels[(i * 4) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue
|
|
pixels[(i * 4) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // (Transparency)
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
}
|
|
|
|
tex.Tag = new string[] { "Format: RGBA16", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
|
|
public static Bitmap decodeIA16(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
if (data.Length >= width * height * 2) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = width * height;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
pixels[(i * 4) + 2] = data[i * 2]; // Red
|
|
pixels[(i * 4) + 1] = data[i * 2]; // Green
|
|
pixels[(i * 4) + 0] = data[i * 2]; // Blue
|
|
pixels[(i * 4) + 3] = data[(i * 2) + 1]; // Alpha
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
}
|
|
tex.Tag = new string[] { "Format: IA16", "Width: " + width,
|
|
"Height: " + height};
|
|
return tex;
|
|
}
|
|
|
|
public static Bitmap decodeIA8(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
if (data.Length >= width * height) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = width * height;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
byte intensity = (byte)(((data[i] >> 4) & 0xF) * 16);
|
|
pixels[(i * 4) + 2] = intensity; // Red
|
|
pixels[(i * 4) + 1] = intensity; // Green
|
|
pixels[(i * 4) + 0] = intensity; // Blue
|
|
pixels[(i * 4) + 3] = (byte)((data[i] & 0xF) * 16); // Alpha
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
}
|
|
tex.Tag = new string[] { "Format: IA8", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
public static Bitmap decodeIA4(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
|
|
if (data.Length >= (width * height) / 2) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = (width * height) / 2;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
byte twoPixels = data[i];
|
|
|
|
byte intensity = (byte)((twoPixels >> 5) * 32);
|
|
pixels[(i * 8) + 2] = intensity; // Red
|
|
pixels[(i * 8) + 1] = intensity; // Green
|
|
pixels[(i * 8) + 0] = intensity; // Blue
|
|
pixels[(i * 8) + 3] = (byte)(((twoPixels >> 4) & 0x1) * 255); // Alpha
|
|
|
|
intensity = (byte)(((twoPixels >> 1) & 0x7) * 32);
|
|
pixels[(i * 8) + 6] = intensity; // Red
|
|
pixels[(i * 8) + 5] = intensity; // Green
|
|
pixels[(i * 8) + 4] = intensity; // Blue
|
|
pixels[(i * 8) + 7] = (byte)((twoPixels & 0x1) * 255); // Alpha
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
tex.Tag = new string[] { "Format: IA4", "Width: " + width,
|
|
"Height: " + height };
|
|
}
|
|
return tex;
|
|
}
|
|
public static Bitmap decodeI8(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
|
|
if (data.Length >= width * height) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = width * height;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
byte intensity = data[i];
|
|
pixels[(i * 4) + 2] = intensity; // Red
|
|
pixels[(i * 4) + 1] = intensity; // Green
|
|
pixels[(i * 4) + 0] = intensity; // Blue
|
|
pixels[(i * 4) + 3] = 0xFF; // Alpha
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
|
|
tex.Tag = new string[] { "Format: I8", "Width: " + width,
|
|
"Height: " + height };
|
|
}
|
|
return tex;
|
|
}
|
|
public static Bitmap decodeI4(byte[] data, int width, int height)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
|
|
if (data.Length >= (width * height) / 2) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = (width * height) / 2;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
byte twoPixels = data[i];
|
|
|
|
byte intensity = (byte)((twoPixels >> 4) * 16);
|
|
pixels[(i * 8) + 2] = intensity; // Red
|
|
pixels[(i * 8) + 1] = intensity; // Green
|
|
pixels[(i * 8) + 0] = intensity; // Blue
|
|
pixels[(i * 8) + 3] = 0xFF; // Alpha
|
|
|
|
intensity = (byte)((twoPixels & 0xF) * 16);
|
|
pixels[(i * 8) + 6] = intensity; // Red
|
|
pixels[(i * 8) + 5] = intensity; // Green
|
|
pixels[(i * 8) + 4] = intensity; // Blue
|
|
pixels[(i * 8) + 7] = 0xFF; // Alpha
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
}
|
|
tex.Tag = new string[] { "Format: I4", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
|
|
public static Bitmap decodeCI4(byte[] data, int width, int height, ushort[] palette)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
|
|
if (data.Length >= (width * height) / 2) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = (width * height) / 2;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
ushort pixel = palette[(data[i] >> 4) & 0xF];
|
|
pixels[(i * 8) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red
|
|
pixels[(i * 8) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green
|
|
pixels[(i * 8) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue
|
|
pixels[(i * 8) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // Alpha
|
|
|
|
pixel = palette[(data[i]) & 0xF];
|
|
pixels[(i * 8) + 6] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red
|
|
pixels[(i * 8) + 5] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green
|
|
pixels[(i * 8) + 4] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue
|
|
pixels[(i * 8) + 7] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // Alpha
|
|
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
}
|
|
tex.Tag = new string[] { "Format: CI4", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
|
|
public static Bitmap decodeCI8(byte[] data, int width, int height, ushort[] palette)
|
|
{
|
|
Bitmap tex = new Bitmap(width, height);
|
|
|
|
if (data.Length >= width * height) // Sanity Check
|
|
{
|
|
BitmapData bitmapData = tex.LockBits(new Rectangle(0, 0, width, height),
|
|
ImageLockMode.ReadWrite, tex.PixelFormat);
|
|
byte[] pixels = new byte[width * height * 4];
|
|
|
|
int len = width * height;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
ushort pixel = palette[data[i]];
|
|
pixels[(i * 4) + 2] = (byte)(((pixel >> 11) & 0x1F) * 8); // Red
|
|
pixels[(i * 4) + 1] = (byte)(((pixel >> 6) & 0x1F) * 8); // Green
|
|
pixels[(i * 4) + 0] = (byte)(((pixel >> 1) & 0x1F) * 8); // Blue
|
|
pixels[(i * 4) + 3] = (pixel & 1) > 0 ? (byte)0xFF : (byte)0x00; // (Transparency)
|
|
//tex.SetPixel(i % width, i / width, Color.FromArgb(alpha, red, green, blue));
|
|
}
|
|
Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
|
|
tex.UnlockBits(bitmapData);
|
|
}
|
|
tex.Tag = new string[] { "Format: CI8", "Width: " + width,
|
|
"Height: " + height };
|
|
return tex;
|
|
}
|
|
}
|
|
}
|