diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 10d71770da..392d373929 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -382,6 +382,7 @@
+
diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs
index d92b61b269..f8ad75b5f6 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs
@@ -132,6 +132,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
[DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void snes_dequeue_message(IntPtr strBuffer);
+ [DllImport("libsneshawk.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void snes_set_color_lut(IntPtr colors);
+
public static bool HasMessage { get { return snes_poll_message() != -1; } }
public static string DequeueMessage()
@@ -404,6 +407,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
scanlineStart_cb = new LibsnesDll.snes_scanlineStart_t(snes_scanlineStart);
+ // set palette
+ int[] tmp = SnesColors.GetLUT(SnesColors.ColorType.Bizhawk);
+ fixed (int* p = &tmp[0])
+ BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_color_lut((IntPtr)p);
+
+
// start up audio resampler
InitAudio();
diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs
index b50d7162e1..a97373c4da 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/SNESGraphicsDecoder.cs
@@ -299,7 +299,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
//the same basic color table that libsnes uses to convert from snes 555 to rgba32
- public static int[] colortable = new int[16 * 32768];
+ public static int[] colortable;
static int[] directColorTable = new int[256]; //8bpp gfx -> rgb555
static SNESGraphicsDecoder()
{
@@ -315,35 +315,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
int color = (b << 10) | (g << 5) | r;
directColorTable[i] = color;
}
-
- //make colortable
- //this is unlikely to change, so maybe we could precompute it to save bootup time.. benchmark it.
- //alternatively, we could drag it out of libsneshawk dll
- for (int l = 0; l < 16; l++)
- {
- for (int r = 0; r < 32; r++)
- {
- for (int g = 0; g < 32; g++)
- {
- for (int b = 0; b < 32; b++)
- {
- //zero 04-sep-2012 - go ahead and turn this into a pixel format we'll want
- //double luma = (double)l / 15.0;
- //int ar = (int)(luma * r + 0.5);
- //int ag = (int)(luma * g + 0.5);
- //int ab = (int)(luma * b + 0.5);
- //ar = ar * 255 / 31;
- //ag = ag * 255 / 31;
- //ab = ab * 255 / 31;
- int ar = (r * l * 17 + 15) / 31;
- int ag = (g * l * 17 + 15) / 31;
- int ab = (b * l * 17 + 15) / 31;
- int color = (ab << 16) + (ag << 8) + (ar << 0) | unchecked((int)0xFF000000);
- colortable[(l << 15) + (r << 10) + (g << 5) + (b << 0)] = color;
- }
- }
- }
- }
+ colortable = SnesColors.GetLUT(SnesColors.ColorType.Bizhawk);
}
byte* vram;
diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/SnesColors.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/SnesColors.cs
new file mode 100644
index 0000000000..1afbf7b597
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/SnesColors.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Consoles.Nintendo.SNES
+{
+ public static class SnesColors
+ {
+ // the SNES renders colors in a 15 bit RGB space. in addition, there is a 4 bit "luma" or "brightness" register
+ // we want to map this to a 24 bit RGB space; the exactly authentic way to do this is not known
+
+ // none of this is optimized for speed because we make a LUT at load time
+
+ public static void BizColor(out int or, out int og, out int ob, int l, int r, int g, int b)
+ {
+ // bizhawk through r3808, from bsnes
+ double luma = (double)l / 15.0;
+ int ar = (int)(luma * r + 0.5);
+ int ag = (int)(luma * g + 0.5);
+ int ab = (int)(luma * b + 0.5);
+ or = ar * 255 / 31;
+ og = ag * 255 / 31;
+ ob = ab * 255 / 31;
+ }
+
+ public static void NattColor(out int or, out int og, out int ob, int l, int r, int g, int b)
+ {
+ // bizhawk r3809. assumes that luma mixing is done in analog
+ or = (r * l * 17 + 15) / 31;
+ og = (g * l * 17 + 15) / 31;
+ ob = (b * l * 17 + 15) / 31;
+ }
+
+ // LUT from snes9x
+ static byte[,] mul_brightness =
+{
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
+{ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04 },
+{ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06 },
+{ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04,
+0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08 },
+{ 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05,
+0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a },
+{ 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06,
+0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c },
+{ 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07,
+0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e },
+{ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08,
+0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x11 },
+{ 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09,
+0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x13 },
+{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x09, 0x0a,
+0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15 },
+{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b,
+0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17 },
+{ 0x00, 0x01, 0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c,
+0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x16, 0x16, 0x17, 0x18, 0x19 },
+{ 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0b, 0x0c, 0x0d,
+0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1b },
+{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d },
+{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }
+};
+
+ public static void Snes9xColor(out int or, out int og, out int ob, int l, int r, int g, int b)
+ {
+ int ar = mul_brightness[l, r];
+ int ag = mul_brightness[l, r];
+ int ab = mul_brightness[l, r];
+ or = ar * 8;
+ og = ag * 8;
+ ob = ab * 8;
+ }
+
+ public enum ColorType
+ {
+ Bizhawk,
+ Natt,
+ Snes9x
+ };
+
+ public static int[] GetLUT(ColorType t)
+ {
+ int[] ret = new int[16 * 32768];
+ for (int l = 0; l < 16; l++)
+ {
+ for (int r = 0; r < 32; r++)
+ {
+ for (int g = 0; g < 32; g++)
+ {
+ for (int b = 0; b < 32; b++)
+ {
+ int ar, ag, ab;
+ if (t == ColorType.Snes9x)
+ Snes9xColor(out ar, out ag, out ab, l, r, g, b);
+ else if (t == ColorType.Natt)
+ NattColor(out ar, out ag, out ab, l, r, g, b);
+ else
+ BizColor(out ar, out ag, out ab, l, r, g, b);
+ int color = (ar << 16) + (ag << 8) + (ab << 0) | unchecked((int)0xFF000000);
+ ret[(l << 15) + (b << 10) + (g << 5) + (r << 0)] = color;
+ }
+ }
+ }
+ }
+ return ret;
+ }
+ }
+}
diff --git a/BizHawk.MultiClient/output/dll/libsneshawk.dll b/BizHawk.MultiClient/output/dll/libsneshawk.dll
index ec4c27a535..e843d01660 100644
Binary files a/BizHawk.MultiClient/output/dll/libsneshawk.dll and b/BizHawk.MultiClient/output/dll/libsneshawk.dll differ
diff --git a/libsnes/bsnes/target-libsnes/libsnes.cpp b/libsnes/bsnes/target-libsnes/libsnes.cpp
index 8c18edebf0..a4709be93c 100644
--- a/libsnes/bsnes/target-libsnes/libsnes.cpp
+++ b/libsnes/bsnes/target-libsnes/libsnes.cpp
@@ -98,34 +98,6 @@ struct Interface : public SNES::Interface {
buffer = new uint32_t[512 * 480];
palette = new uint32_t[16 * 32768];
- //{llll bbbbb ggggg rrrrr} -> { rrrrr ggggg bbbbb }
- for(unsigned l = 0; l < 16; l++) {
- for(unsigned r = 0; r < 32; r++) {
- for(unsigned g = 0; g < 32; g++) {
- for(unsigned b = 0; b < 32; b++) {
- //double luma = (double)l / 15.0;
- //unsigned ar = (luma * r + 0.5);
- //unsigned ag = (luma * g + 0.5);
- //unsigned ab = (luma * b + 0.5);
- //palette[(l << 15) + (r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0);
-
- //zero 04-sep-2012 - go ahead and turn this into a pixel format we'll want
- //double luma = (double)l / 15.0;
- //unsigned ar = (luma * r + 0.5);
- //unsigned ag = (luma * g + 0.5);
- //unsigned ab = (luma * b + 0.5);
- //ar = ar * 255 / 31;
- //ag = ag * 255 / 31;
- //ab = ab * 255 / 31;
- int ar = (r * l * 17 + 15) / 31;
- int ag = (g * l * 17 + 15) / 31;
- int ab = (b * l * 17 + 15) / 31;
- unsigned color = (ab << 16) + (ag << 8) + (ar << 0) | 0xFF000000;
- palette[(l << 15) + (r << 10) + (g << 5) + (b << 0)] = color;
- }
- }
- }
- }
}
~Interface() {
@@ -153,6 +125,11 @@ void snes_set_video_refresh(snes_video_refresh_t video_refresh) {
interface.pvideo_refresh = video_refresh;
}
+void snes_set_color_lut(uint32_t * colors) {
+ for (int i = 0; i < 16 * 32768; i++)
+ interface.palette[i] = colors[i];
+}
+
void snes_set_audio_sample(snes_audio_sample_t audio_sample) {
interface.paudio_sample = audio_sample;
}
diff --git a/libsnes/bsnes/target-libsnes/libsnes.hpp b/libsnes/bsnes/target-libsnes/libsnes.hpp
index 8aef662b2c..e7078ad569 100644
--- a/libsnes/bsnes/target-libsnes/libsnes.hpp
+++ b/libsnes/bsnes/target-libsnes/libsnes.hpp
@@ -143,6 +143,8 @@ void snes_dequeue_message(char* buffer);
typedef const char* (*snes_path_request_t)(int slot, const char* hint);
void snes_set_path_request(snes_path_request_t path_request);
+void snes_set_color_lut(uint32_t * colors);
+
// system bus implementation
uint8_t bus_read(unsigned addr);
void bus_write(unsigned addr, uint8_t val);