Projektdateien hinzufügen.

This commit is contained in:
2024-05-05 15:59:49 +02:00
parent 74da0c6962
commit 7c28a6ee17
242 changed files with 23697 additions and 0 deletions

View File

@@ -0,0 +1,524 @@
using System.Drawing;
namespace SM64Lib.N64Graphics
{
public enum N64Codec { RGBA16, RGBA32, IA16, IA8, IA4, I8, I4, CI8, CI4, ONEBPP };
public enum N64IMode { AlphaCopyIntensity, AlphaBinary, AlphaOne };
public class N64Graphics
{
private static int SCALE_5_8(int val)
{
return (val * 0xFF) / 0x1F;
}
private static byte SCALE_8_5(byte val)
{
return (byte)((((val) + 4) * 0x1F) / 0xFF);
}
private static byte SCALE_8_4(byte val)
{
return (byte)(val / 0x11);
}
private static int SCALE_3_8(byte val)
{
return (val * 0xFF) / 0x7;
}
private static byte SCALE_8_3(byte val)
{
return (byte)(val / 0x24);
}
public static Color RGBA16Color(byte c0, byte c1)
{
int r = SCALE_5_8((c0 & 0xF8) >> 3);
int g = SCALE_5_8(((c0 & 0x07) << 2) | ((c1 & 0xC0) >> 6));
int b = SCALE_5_8((c1 & 0x3E) >> 1);
int a = ((c1 & 0x1) > 0) ? 255 : 0;
return Color.FromArgb(a, r, g, b);
}
public static void ColorRGBA16(Color col, out byte c0, out byte c1)
{
byte r, g, b;
r = SCALE_8_5(col.R);
g = SCALE_8_5(col.G);
b = SCALE_8_5(col.B);
c0 = (byte)((r << 3) | (g >> 2));
c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0));
}
public static Color RGBA16Color(byte[] data, int pixOffset)
{
byte c0 = data[pixOffset];
byte c1 = data[pixOffset + 1];
return RGBA16Color(c0, c1);
}
public static Color RGBA32Color(byte[] data, int pixOffset)
{
int r, g, b, a;
r = data[pixOffset];
g = data[pixOffset + 1];
b = data[pixOffset + 2];
a = data[pixOffset + 3];
return Color.FromArgb(a, r, g, b);
}
public static Color IA16Color(byte[] data, int pixOffset)
{
int i = data[pixOffset];
int a = data[pixOffset + 1];
return Color.FromArgb(a, i, i, i);
}
public static Color IA8Color(byte[] data, int pixOffset)
{
int i, a;
byte c = data[pixOffset];
i = (c >> 4) * 0x11;
a = (c & 0xF) * 0x11;
return Color.FromArgb(a, i, i, i);
}
public static Color IA4Color(byte[] data, int pixOffset, int nibble)
{
int shift = (1 - nibble) * 4;
int i, a;
int val = (data[pixOffset] >> shift) & 0xF;
i = SCALE_3_8((byte)(val >> 1));
a = (val & 0x1) > 0 ? 0xFF : 0x00;
return Color.FromArgb(a, i, i, i);
}
public static Color I8Color(byte[] data, int pixOffset, N64IMode mode = N64IMode.AlphaCopyIntensity)
{
int i = data[pixOffset];
int a = i;
switch (mode)
{
case N64IMode.AlphaBinary: a = (i == 0) ? 0 : 0xFF; break;
case N64IMode.AlphaCopyIntensity: a = i; break;
case N64IMode.AlphaOne: a = 0xFF; break;
}
return Color.FromArgb(a, i, i, i);
}
public static Color I4Color(byte[] data, int pixOffset, int nibble, N64IMode mode = N64IMode.AlphaCopyIntensity)
{
int shift = (1 - nibble) * 4;
int i = (data[pixOffset] >> shift) & 0xF;
i *= 0x11;
int a = i;
switch (mode)
{
case N64IMode.AlphaBinary: a = (i == 0) ? 0 : 0xFF; break;
case N64IMode.AlphaCopyIntensity: a = i; break;
case N64IMode.AlphaOne: a = 0xFF; break;
}
return Color.FromArgb(a, i, i, i);
}
public static Color CI8Color(byte[] data, byte[] palette, int pixOffset)
{
byte c0, c1;
int palOffset = 2 * data[pixOffset];
c0 = palette[palOffset];
c1 = palette[palOffset + 1];
return RGBA16Color(c0, c1);
}
public static Color CI4Color(byte[] data, byte[] palette, int pixOffset, int nibble)
{
byte c0, c1;
int shift = (1 - nibble) * 4;
int palOffset = 2 * ((data[pixOffset] >> shift) & 0xF);
c0 = palette[palOffset];
c1 = palette[palOffset + 1];
return RGBA16Color(c0, c1);
}
public static Color BPPColor(byte[] data, int pixOffset, int bit)
{
int i, a;
int val = (data[pixOffset] >> (7 - bit)) & 0x1;
i = a = val == 0 ? 0x00 : 0xFF;
return Color.FromArgb(a, i, i, i);
}
// return number of bytes needed to encode numPixels using codec
public static int PixelsToBytes(N64Codec codec, int numPixels)
{
int numBytes = 0;
switch (codec)
{
case N64Codec.RGBA16: numBytes = numPixels * 2; break;
case N64Codec.RGBA32: numBytes = numPixels * 4; break;
case N64Codec.IA16: numBytes = numPixels * 2; break;
case N64Codec.IA8: numBytes = numPixels; break;
case N64Codec.IA4: numBytes = numPixels / 2; break;
case N64Codec.I8: numBytes = numPixels; break;
case N64Codec.I4: numBytes = numPixels / 2; break;
case N64Codec.CI8: numBytes = numPixels; break;
case N64Codec.CI4: numBytes = numPixels / 2; break;
case N64Codec.ONEBPP: numBytes = numPixels / 8; break;
}
return numBytes;
}
public static string CodecString(N64Codec codec)
{
switch (codec)
{
case N64Codec.RGBA16: return "rgba16";
case N64Codec.RGBA32: return "rgba32";
case N64Codec.IA16: return "ia16";
case N64Codec.IA8: return "ia8";
case N64Codec.IA4: return "ia4";
case N64Codec.I8: return "i8";
case N64Codec.I4: return "i4";
case N64Codec.CI8: return "ci8";
case N64Codec.CI4: return "ci4";
case N64Codec.ONEBPP: return "1bpp";
}
return "unk";
}
public static N64Codec StringCodec(string str)
{
switch (str.ToLower())
{
default:
case "rgba16": return N64Codec.RGBA16;
case "rgba32": return N64Codec.RGBA32;
case "ia16": return N64Codec.IA16;
case "ia8": return N64Codec.IA8;
case "ia4": return N64Codec.IA4;
case "i8": return N64Codec.I8;
case "i4": return N64Codec.I4;
case "ci8": return N64Codec.CI8;
case "ci4": return N64Codec.CI4;
case "1bpp": return N64Codec.ONEBPP;
}
}
public static Color MakeColor(byte[] data, byte[] palette, int offset, int select, N64Codec codec, N64IMode mode)
{
Color color;
switch (codec)
{
case N64Codec.RGBA16:
color = RGBA16Color(data, offset);
break;
case N64Codec.RGBA32:
color = RGBA32Color(data, offset);
break;
case N64Codec.IA16:
color = IA16Color(data, offset);
break;
case N64Codec.IA8:
color = IA8Color(data, offset);
break;
case N64Codec.IA4:
color = IA4Color(data, offset, select);
break;
case N64Codec.I8:
color = I8Color(data, offset, mode);
break;
case N64Codec.I4:
color = I4Color(data, offset, select, mode);
break;
case N64Codec.CI8:
color = CI8Color(data, palette, offset);
break;
case N64Codec.CI4:
color = CI4Color(data, palette, offset, select);
break;
case N64Codec.ONEBPP:
color = BPPColor(data, offset, select);
break;
default:
color = RGBA16Color(data, offset);
break;
}
return color;
}
public static void RenderTexture(Graphics g, byte[] data, byte[] palette, int offset, int width, int height, int scale, N64Codec codec, N64IMode mode)
{
Brush brush;
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++)
{
int pixOffset = (h * width + w);
int bytesPerPix = 1;
int select = 0;
switch (codec)
{
case N64Codec.RGBA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break;
case N64Codec.RGBA32: bytesPerPix = 4; pixOffset *= bytesPerPix; break;
case N64Codec.IA16: bytesPerPix = 2; pixOffset *= bytesPerPix; break;
case N64Codec.IA8: break;
case N64Codec.IA4:
select = pixOffset & 0x1;
pixOffset /= 2;
break;
case N64Codec.I8: break;
case N64Codec.I4:
case N64Codec.CI4:
select = pixOffset & 0x1;
pixOffset /= 2;
break;
case N64Codec.CI8: break;
case N64Codec.ONEBPP:
select = pixOffset & 0x7;
pixOffset /= 8;
break;
}
pixOffset += offset;
if (data.Length > pixOffset + bytesPerPix - 1)
{
brush = new SolidBrush(MakeColor(data, palette, pixOffset, select, codec, mode));
g.FillRectangle(brush, w * scale, h * scale, scale, scale);
}
}
}
}
// return palette index of matching c0/c1 16-bit dataset, or -1 if not found
private static int paletteIndex(byte[] pal, int palCount, byte c0, byte c1)
{
for (int i = 0; i < palCount; i++)
{
if (pal[2 * i] == c0 && pal[2 * i + 1] == c1)
{
return i;
}
}
return -1;
}
public static void Convert(ref byte[] imageData, ref byte[] paletteData, N64Codec codec, Bitmap bm)
{
int numPixels = bm.Width * bm.Height;
imageData = new byte[PixelsToBytes(codec, numPixels)];
int palCount = 0;
switch (codec)
{
case N64Codec.RGBA16:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
byte c0;
byte c1;
ColorRGBA16(col, out c0, out c1);
int idx = 2 * (y * bm.Width + x);
imageData[idx + 0] = c0;
imageData[idx + 1] = c1;
}
}
break;
case N64Codec.RGBA32:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int idx = 4 * (y * bm.Width + x);
imageData[idx + 0] = col.R;
imageData[idx + 1] = col.G;
imageData[idx + 2] = col.B;
imageData[idx + 3] = col.A;
}
}
break;
case N64Codec.IA16:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int sum = col.R + col.G + col.B;
byte intensity = (byte)(sum / 3);
byte alpha = col.A;
int idx = 2 * (y * bm.Width + x);
imageData[idx + 0] = intensity;
imageData[idx + 1] = alpha;
}
}
break;
case N64Codec.IA8:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int sum = col.R + col.G + col.B;
byte intensity = SCALE_8_4((byte)(sum / 3));
byte alpha = SCALE_8_4(col.A);
int idx = y * bm.Width + x;
imageData[idx] = (byte)((intensity << 4) | alpha);
}
}
break;
case N64Codec.IA4:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int sum = col.R + col.G + col.B;
byte intensity = SCALE_8_3((byte)(sum / 3));
byte alpha = (byte)(col.A > 0 ? 1 : 0);
int idx = y * bm.Width + x;
byte old = imageData[idx / 2];
if ((idx % 2) > 0)
{
imageData[idx / 2] = (byte)((old & 0xF0) | (intensity << 1) | alpha);
}
else
{
imageData[idx / 2] = (byte)((old & 0x0F) | (((intensity << 1) | alpha) << 4));
}
}
}
break;
case N64Codec.I8:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int sum = col.R + col.G + col.B;
byte intensity = (byte)(sum / 3);
int idx = y * bm.Width + x;
imageData[idx] = intensity;
}
}
break;
case N64Codec.I4:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int sum = col.R + col.G + col.B;
byte intensity = SCALE_8_4((byte)(sum / 3));
int idx = y * bm.Width + x;
byte old = imageData[idx / 2];
if ((idx % 2) > 0)
{
imageData[idx / 2] = (byte)((old & 0xF0) | intensity);
}
else
{
imageData[idx / 2] = (byte)((old & 0x0F) | (intensity << 4));
}
}
}
break;
case N64Codec.CI4:
paletteData = new byte[16 * 2];
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
byte r, g, b;
r = SCALE_8_5(col.R);
g = SCALE_8_5(col.G);
b = SCALE_8_5(col.B);
byte c0 = (byte)((r << 3) | (g >> 2));
byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0));
int idx = y * bm.Width + x;
int palIdx = paletteIndex(paletteData, palCount, c0, c1);
if (palIdx < 0)
{
if (palCount < paletteData.Length / 2)
{
palIdx = palCount;
paletteData[2 * palCount] = c0;
paletteData[2 * palCount + 1] = c1;
palCount++;
}
else
{
palIdx = 0;
// TODO: out of palette entries. error or pick closest?
}
}
byte old = imageData[idx / 2];
if ((idx % 2) > 0)
{
imageData[idx / 2] = (byte)((old & 0xF0) | (byte)palIdx);
}
else
{
imageData[idx / 2] = (byte)((old & 0x0F) | ((byte)palIdx << 4));
}
}
}
break;
case N64Codec.CI8:
paletteData = new byte[256 * 2];
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
byte r, g, b;
r = SCALE_8_5(col.R);
g = SCALE_8_5(col.G);
b = SCALE_8_5(col.B);
byte c0 = (byte)((r << 3) | (g >> 2));
byte c1 = (byte)(((g & 0x3) << 6) | (b << 1) | ((col.A > 0) ? 1 : 0));
int idx = y * bm.Width + x;
int palIdx = paletteIndex(paletteData, palCount, c0, c1);
if (palIdx < 0)
{
if (palCount < paletteData.Length / 2)
{
palIdx = palCount;
paletteData[2 * palCount] = c0;
paletteData[2 * palCount + 1] = c1;
palCount++;
}
else
{
palIdx = 0;
// TODO: out of palette entries. error or pick closest?
}
}
imageData[idx] = (byte)palIdx;
}
}
break;
case N64Codec.ONEBPP:
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
Color col = bm.GetPixel(x, y);
int sum = col.R + col.G + col.B;
byte intensity = (sum > 0) ? (byte)1 : (byte)0;
int idx = y * bm.Width + x;
byte old = imageData[idx / 8];
int bit = idx % 8;
int mask = ~(1 << bit);
imageData[idx / 8] = (byte)((old & mask) | (intensity << bit));
}
}
break;
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar
// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("d9258483-950c-46d1-a333-31f32492cd7e")]

View File

@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<AssemblyTitle>N64Graphics</AssemblyTitle>
<Company>Pilzinsel64</Company>
<Product>N64Graphics</Product>
<Copyright>Copyright © Pilzinsel64 2017 - 2018</Copyright>
<UseWindowsForms>true</UseWindowsForms>
<Platforms>AnyCPU</Platforms>
<Configurations>Debug;Release;ReleaseBundle;ReleaseStandalone</Configurations>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
</ItemGroup>
<ItemGroup>
<Compile Remove="obj\RelMono\TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs" />
<Compile Remove="obj\RelMono\TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs" />
<Compile Remove="obj\RelMono\TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,598 @@
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;
}
}
}