66 lines
2.7 KiB
C#
66 lines
2.7 KiB
C#
using System;
|
|
using StoicGoose.Core.Interfaces;
|
|
|
|
namespace StoicGoose.Core.Display
|
|
{
|
|
public static class DisplayUtilities
|
|
{
|
|
// TODO: WSC high contrast mode
|
|
|
|
private static ushort ReadMemory16(IMachine machine, uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
|
|
private static uint ReadMemory32(IMachine machine, uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
|
|
|
|
public static byte ReadPixel(IMachine machine, ushort tile, int y, int x, bool isPacked, bool is4bpp, bool isColor)
|
|
{
|
|
/* http://perfectkiosk.net/stsws.html#color_mode */
|
|
|
|
/* WonderSwan OR Color/Crystal in 2bpp mode */
|
|
if (!isColor || (isColor && !is4bpp))
|
|
{
|
|
var data = ReadMemory16(machine, (uint)(0x2000 + (tile << 4) + ((y % 8) << 1)));
|
|
return (byte)((((data >> 15 - (x % 8)) & 0b1) << 1 | ((data >> 7 - (x % 8)) & 0b1)) & 0b11);
|
|
}
|
|
|
|
/* WonderSwan Color/Crystal in 4bpp mode */
|
|
else if (isColor && is4bpp)
|
|
{
|
|
/* 4bpp planar mode */
|
|
if (!isPacked)
|
|
{
|
|
var data = ReadMemory32(machine, (uint)(0x4000 + ((tile & 0x03FF) << 5) + ((y % 8) << 2)));
|
|
return (byte)((((data >> 31 - (x % 8)) & 0b1) << 3 | ((data >> 23 - (x % 8)) & 0b1) << 2 | ((data >> 15 - (x % 8)) & 0b1) << 1 | ((data >> 7 - (x % 8)) & 0b1)) & 0b1111);
|
|
}
|
|
|
|
/* 4bpp packed mode */
|
|
else if (isPacked)
|
|
{
|
|
var data = machine.ReadMemory((ushort)(0x4000 + ((tile & 0x03FF) << 5) + ((y % 8) << 2) + ((x % 8) >> 1)));
|
|
return (byte)((data >> 4 - (((x % 8) & 0b1) << 2)) & 0b1111);
|
|
}
|
|
}
|
|
|
|
throw new Exception("Invalid display controller configuration");
|
|
}
|
|
|
|
public static ushort ReadColor(IMachine machine, byte paletteIdx, byte colorIdx)
|
|
{
|
|
var address = (uint)(0x0FE00 + (paletteIdx << 5) + (colorIdx << 1));
|
|
return (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address));
|
|
}
|
|
|
|
private static byte DuplicateBits(int value) => (byte)((value & 0b1111) | (value & 0b1111) << 4);
|
|
|
|
public static (byte r, byte g, byte b) GeneratePixel(byte data) => (DuplicateBits(data), DuplicateBits(data), DuplicateBits(data));
|
|
public static (byte r, byte g, byte b) GeneratePixel(ushort data) => (DuplicateBits(data >> 8), DuplicateBits(data >> 4), DuplicateBits(data >> 0));
|
|
|
|
public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4);
|
|
public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, long address)
|
|
{
|
|
data[address + 0] = pixel.r;
|
|
data[address + 1] = pixel.g;
|
|
data[address + 2] = pixel.b;
|
|
data[address + 3] = 255;
|
|
}
|
|
}
|
|
}
|