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);