libdgf/LibDgf/Ps2/Gs/PsmtMixer.cs
2021-03-17 03:18:15 -06:00

141 lines
5 KiB
C#

using LibDgf.Txm;
using System;
using System.Collections.Generic;
using System.Text;
namespace LibDgf.Ps2.Gs
{
public static class PsmtMixer
{
static int[,] PSMCT32_TO_PSMT4_COL02_LOOKUP = new int[16, 8];
static int[,] PSMCT32_TO_PSMT4_COL13_LOOKUP = new int[16, 8];
static int[,] PSMCT32_TO_PSMT8_COL02_LOOKUP = new int[16, 4];
static int[,] PSMCT32_TO_PSMT8_COL13_LOOKUP = new int[16, 4];
static PsmtMixer()
{
FillLookup(PSMCT32_TO_PSMT4_COL02_LOOKUP, false);
FillOddLookup(PSMCT32_TO_PSMT4_COL02_LOOKUP, PSMCT32_TO_PSMT4_COL13_LOOKUP);
FillLookup(PSMCT32_TO_PSMT8_COL02_LOOKUP, false);
FillOddLookup(PSMCT32_TO_PSMT8_COL02_LOOKUP, PSMCT32_TO_PSMT8_COL13_LOOKUP);
//PrintLookup(PSMCT32_TO_PSMT4_COL02_LOOKUP, nameof(PSMCT32_TO_PSMT4_COL02_LOOKUP));
//PrintLookup(PSMCT32_TO_PSMT4_COL13_LOOKUP, nameof(PSMCT32_TO_PSMT4_COL13_LOOKUP));
//PrintLookup(PSMCT32_TO_PSMT8_COL02_LOOKUP, nameof(PSMCT32_TO_PSMT8_COL02_LOOKUP));
//PrintLookup(PSMCT32_TO_PSMT8_COL13_LOOKUP, nameof(PSMCT32_TO_PSMT8_COL13_LOOKUP));
}
static void PrintLookup(int[,] lookup, string name)
{
Console.WriteLine(name);
int rowNum = lookup.GetLength(0);
int colNum = lookup.GetLength(1);
for (int row = 0; row < rowNum; ++row)
{
for (int col = colNum - 1; col >= 0; --col)
{
Console.Write("{0,3} ", lookup[row, col]);
}
Console.WriteLine();
}
Console.WriteLine();
}
static void FillLookup(int[,] lookup, bool skipNonConsec)
{
int numCols = lookup.GetLength(1);
int num = 0;
// Phase 1: consecutive numbers
// Fill every second column
// Top half then bottom half
for (int half = 0; half < 2; ++half)
{
for (int col = 0; col < numCols; col += skipNonConsec ? 1 : 2)
{
for (int row = 0; row < 8; ++row)
{
lookup[half * 8 + row, col] = num++;
}
}
}
// Phase 2: wrapped numbers
if (!skipNonConsec)
{
for (int half = 0; half < 2; ++half)
{
for (int col = 1; col < numCols; col += 2)
{
for (int row = 4; row < 12; ++row)
{
lookup[half * 8 + (row % 8), col] = num++;
}
}
}
}
}
static void FillOddLookup(int[,] evenLookup, int[,] oddLookup)
{
int numCols = evenLookup.GetLength(1);
for (int half = 0; half < 2; ++half)
{
for (int i = 0; i < 8; ++i)
{
for (int j = 0; j < numCols; ++j)
{
oddLookup[half * 8 + i, j] = evenLookup[half * 8 + ((i + 4) % 8), j];
}
}
}
}
public static byte[] MixColumn(byte[] column, TxmPixelFormat srcFormat, TxmPixelFormat destFormat, bool isOdd)
{
if (srcFormat != TxmPixelFormat.PSMCT32)
throw new NotSupportedException("Only PSMCT32 supported as source format.");
switch (destFormat)
{
case TxmPixelFormat.PSMT4:
return MixColumn32To4(column, isOdd);
case TxmPixelFormat.PSMT8:
return MixColumn32To8(column, isOdd);
default:
throw new NotSupportedException($"{destFormat} not supported as destination format.");
}
}
static byte[] MixColumn32To4(byte[] column, bool isOdd)
{
int[,] lookup = isOdd ? PSMCT32_TO_PSMT4_COL13_LOOKUP : PSMCT32_TO_PSMT4_COL02_LOOKUP;
int numCol = lookup.GetLength(1);
byte[] dest = new byte[column.Length];
byte b = 0;
for (int i = 0; i < column.Length * 2; ++i)
{
if (i % 2 == 0)
b = column[i / 2];
else
b >>= 4;
int index = lookup[i / numCol, i % numCol];
dest[index / 2] |= (byte)((b & 0x0f) << (index % 2 * 4));
}
return dest;
}
static byte[] MixColumn32To8(byte[] column, bool isOdd)
{
int[,] lookup = isOdd ? PSMCT32_TO_PSMT8_COL13_LOOKUP : PSMCT32_TO_PSMT8_COL02_LOOKUP;
int numCol = lookup.GetLength(1);
byte[] dest = new byte[column.Length];
for (int i = 0; i < column.Length; ++i)
{
int index = lookup[i / numCol, i % numCol];
dest[index] = column[i];
}
return dest;
}
}
}