gambatte: fully implement cgb palette selection

This commit is contained in:
goyuken 2012-11-18 18:46:57 +00:00
parent 5df1cd532e
commit 8d20c2e351
12 changed files with 738 additions and 279 deletions

View File

@ -61,7 +61,7 @@ namespace BizHawk.Emulation.Consoles.GB
}
// vba's default mode
public static Triple VividColor(Triple c)
public static Triple VividVBAColor(Triple c)
{
return c.Bit5to8Bad();
}
@ -96,5 +96,40 @@ namespace BizHawk.Emulation.Consoles.GB
ret.b = (c.r * 2 + c.g * 2 + c.b * 12 + 8) >> 4;
return ret.Bit5to8Bad();
}
// as vivid as possible
public static Triple UltraVividColor(Triple c)
{
return c.Bit5to8Good();
}
public enum ColorType
{
gambatte,
vivid,
vbavivid,
vbagbnew,
vgabgbold
};
public static int[] GetLut(ColorType c)
{
Func<Triple, Triple> f = null;
switch (c)
{
case ColorType.gambatte: f = GambatteColor; break;
case ColorType.vivid: f = UltraVividColor; break;
case ColorType.vbavivid: f = VividVBAColor; break;
case ColorType.vbagbnew: f = NewVBAColor; break;
case ColorType.vgabgbold: f = OldVBAColor; break;
}
int[] ret = new int[32768];
int i = 0;
for (int b = 0; b < 32; b++)
for (int g = 0; g < 32; g++)
for (int r = 0; r < 32; r++)
ret[i++] = f(new Triple(r, g, b)).ToARGB32();
return ret;
}
}
}

View File

@ -50,7 +50,7 @@ namespace BizHawk.Emulation.Consoles.GB
// set real default colors (before anyone mucks with them at all)
ChangeDMGColors(new int[] { 10798341, 8956165, 1922333, 337157, 10798341, 8956165, 1922333, 337157, 10798341, 8956165, 1922333, 337157 });
SetCGBColors();
SetCGBColors(GBColors.ColorType.gambatte);
InitSound();
@ -707,14 +707,9 @@ namespace BizHawk.Emulation.Consoles.GB
LibGambatte.gambatte_setdmgpalettecolor(GambatteState, (LibGambatte.PalType)(i / 4), (uint)i % 4, (uint)colors[i]);
}
void SetCGBColors()
public void SetCGBColors(GBColors.ColorType type)
{
int[] lut = new int[32768];
int i = 0;
for (int b = 0; b < 32; b++)
for (int g = 0; g < 32; g++)
for (int r = 0; r < 32; r++)
lut[i++] = GBColors.GambatteColor(new GBColors.Triple(r, g, b)).ToARGB32();
int[] lut = GBColors.GetLut(type);
unsafe
{
fixed (int* p = &lut[0])

View File

@ -220,6 +220,12 @@
<Compile Include="GBtools\BmpView.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="GBtools\CGBColorChooserForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="GBtools\CGBColorChooserForm.Designer.cs">
<DependentUpon>CGBColorChooserForm.cs</DependentUpon>
</Compile>
<Compile Include="GBtools\ColorChooserForm.cs">
<SubType>Form</SubType>
</Compile>
@ -479,6 +485,9 @@
<EmbeddedResource Include="config\PathInfo.resx">
<DependentUpon>PathInfo.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="GBtools\CGBColorChooserForm.resx">
<DependentUpon>CGBColorChooserForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="GBtools\ColorChooserForm.resx">
<DependentUpon>ColorChooserForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -710,6 +710,7 @@ namespace BizHawk.MultiClient
public bool GB_MulticartCompat = false;
public string GB_PaletteFile = "";
public bool GB_AsSGB = false;
public Emulation.Consoles.GB.GBColors.ColorType CGBColors = Emulation.Consoles.GB.GBColors.ColorType.gambatte;
//Commodore 64 Settings
public SingleButtonJoyStickTemplate[] C64Joysticks = new SingleButtonJoyStickTemplate[2];

View File

@ -0,0 +1,190 @@
namespace BizHawk.MultiClient.GBtools
{
partial class CGBColorChooserForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.radioButton1 = new System.Windows.Forms.RadioButton();
this.radioButton2 = new System.Windows.Forms.RadioButton();
this.radioButton3 = new System.Windows.Forms.RadioButton();
this.radioButton4 = new System.Windows.Forms.RadioButton();
this.radioButton5 = new System.Windows.Forms.RadioButton();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.buttonOK = new System.Windows.Forms.Button();
this.buttonCancel = new System.Windows.Forms.Button();
this.bmpView1 = new BizHawk.MultiClient.GBtools.BmpView();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.Controls.Add(this.radioButton5);
this.groupBox1.Controls.Add(this.radioButton3);
this.groupBox1.Controls.Add(this.radioButton4);
this.groupBox1.Controls.Add(this.radioButton2);
this.groupBox1.Controls.Add(this.radioButton1);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(132, 132);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Preset Select";
//
// radioButton1
//
this.radioButton1.AutoSize = true;
this.radioButton1.Location = new System.Drawing.Point(6, 19);
this.radioButton1.Name = "radioButton1";
this.radioButton1.Size = new System.Drawing.Size(71, 17);
this.radioButton1.TabIndex = 0;
this.radioButton1.TabStop = true;
this.radioButton1.Text = "Gambatte";
this.radioButton1.UseVisualStyleBackColor = true;
this.radioButton1.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged);
//
// radioButton2
//
this.radioButton2.AutoSize = true;
this.radioButton2.Location = new System.Drawing.Point(6, 42);
this.radioButton2.Name = "radioButton2";
this.radioButton2.Size = new System.Drawing.Size(48, 17);
this.radioButton2.TabIndex = 1;
this.radioButton2.TabStop = true;
this.radioButton2.Text = "Vivid";
this.radioButton2.UseVisualStyleBackColor = true;
this.radioButton2.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged);
//
// radioButton3
//
this.radioButton3.AutoSize = true;
this.radioButton3.Location = new System.Drawing.Point(6, 65);
this.radioButton3.Name = "radioButton3";
this.radioButton3.Size = new System.Drawing.Size(72, 17);
this.radioButton3.TabIndex = 2;
this.radioButton3.TabStop = true;
this.radioButton3.Text = "VBA Vivid";
this.radioButton3.UseVisualStyleBackColor = true;
this.radioButton3.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged);
//
// radioButton4
//
this.radioButton4.AutoSize = true;
this.radioButton4.Location = new System.Drawing.Point(6, 88);
this.radioButton4.Name = "radioButton4";
this.radioButton4.Size = new System.Drawing.Size(92, 17);
this.radioButton4.TabIndex = 1;
this.radioButton4.TabStop = true;
this.radioButton4.Text = "VBA Accurate";
this.radioButton4.UseVisualStyleBackColor = true;
this.radioButton4.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged);
//
// radioButton5
//
this.radioButton5.AutoSize = true;
this.radioButton5.Location = new System.Drawing.Point(6, 111);
this.radioButton5.Name = "radioButton5";
this.radioButton5.Size = new System.Drawing.Size(117, 17);
this.radioButton5.TabIndex = 2;
this.radioButton5.TabStop = true;
this.radioButton5.Text = "VBA Accurate (Old)";
this.radioButton5.UseVisualStyleBackColor = true;
this.radioButton5.CheckedChanged += new System.EventHandler(this.radioButton1_CheckedChanged);
//
// groupBox2
//
this.groupBox2.Controls.Add(this.bmpView1);
this.groupBox2.Location = new System.Drawing.Point(150, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(268, 153);
this.groupBox2.TabIndex = 2;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Preview";
//
// buttonOK
//
this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.buttonOK.Location = new System.Drawing.Point(107, 171);
this.buttonOK.Name = "buttonOK";
this.buttonOK.Size = new System.Drawing.Size(75, 23);
this.buttonOK.TabIndex = 3;
this.buttonOK.Text = "OK";
this.buttonOK.UseVisualStyleBackColor = true;
//
// buttonCancel
//
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.buttonCancel.Location = new System.Drawing.Point(188, 171);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(75, 23);
this.buttonCancel.TabIndex = 4;
this.buttonCancel.Text = "Cancel";
this.buttonCancel.UseVisualStyleBackColor = true;
//
// bmpView1
//
this.bmpView1.Location = new System.Drawing.Point(6, 19);
this.bmpView1.Name = "bmpView1";
this.bmpView1.Size = new System.Drawing.Size(256, 128);
this.bmpView1.TabIndex = 3;
this.bmpView1.Text = "bmpView1";
//
// CGBColorChooserForm
//
this.AcceptButton = this.buttonOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.buttonCancel;
this.ClientSize = new System.Drawing.Size(426, 202);
this.Controls.Add(this.buttonCancel);
this.Controls.Add(this.buttonOK);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Name = "CGBColorChooserForm";
this.Text = "Gameboy Color Palette Config";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.RadioButton radioButton2;
private System.Windows.Forms.RadioButton radioButton1;
private System.Windows.Forms.RadioButton radioButton5;
private System.Windows.Forms.RadioButton radioButton3;
private System.Windows.Forms.RadioButton radioButton4;
private System.Windows.Forms.GroupBox groupBox2;
private BmpView bmpView1;
private System.Windows.Forms.Button buttonOK;
private System.Windows.Forms.Button buttonCancel;
}
}

View File

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BizHawk.Emulation.Consoles.GB;
namespace BizHawk.MultiClient.GBtools
{
public partial class CGBColorChooserForm : Form
{
CGBColorChooserForm()
{
InitializeComponent();
bmpView1.ChangeBitmapSize(bmpView1.Size);
type = Global.Config.CGBColors;
switch (type)
{
case GBColors.ColorType.gambatte: radioButton1.Checked = true; break;
case GBColors.ColorType.vivid: radioButton2.Checked = true; break;
case GBColors.ColorType.vbavivid: radioButton3.Checked = true; break;
case GBColors.ColorType.vbagbnew: radioButton4.Checked = true; break;
case GBColors.ColorType.vgabgbold: radioButton5.Checked = true; break;
}
}
GBColors.ColorType type;
unsafe void RefreshType()
{
var lockdata = bmpView1.bmp.LockBits(new Rectangle(0, 0, 256, 128), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
int[] lut = GBColors.GetLut(type);
int* dest = (int*)lockdata.Scan0;
for (int j = 0; j < 128; j++)
{
for (int i = 0; i < 256; i++)
{
int r = i % 32;
int g = j % 32;
int b = i / 32 * 4 + j / 32;
int color = lut[r | g << 5 | b << 10];
*dest++ = color;
}
dest -= 256;
dest += lockdata.Stride / sizeof(int);
}
bmpView1.bmp.UnlockBits(lockdata);
bmpView1.Refresh();
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if (sender == radioButton1)
type = GBColors.ColorType.gambatte;
if (sender == radioButton2)
type = GBColors.ColorType.vivid;
if (sender == radioButton3)
type = GBColors.ColorType.vbavivid;
if (sender == radioButton4)
type = GBColors.ColorType.vbagbnew;
if (sender == radioButton5)
type = GBColors.ColorType.vgabgbold;
if ((sender as RadioButton).Checked)
RefreshType();
}
public static bool DoCGBColorChooserFormDialog(IWin32Window parent)
{
using (var dlg = new CGBColorChooserForm())
{
var result = dlg.ShowDialog(parent);
if (result == DialogResult.OK)
{
Global.Config.CGBColors = dlg.type;
return true;
}
else
return false;
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

File diff suppressed because it is too large Load Diff

View File

@ -1782,11 +1782,12 @@ namespace BizHawk.MultiClient
private void gBToolStripMenuItem_DropDownOpened(object sender, EventArgs e)
{
// the palettes have no effect when CGB mode is active
/*
if (Global.Emulator is Emulation.Consoles.GB.Gameboy)
{
changeDMGPalettesToolStripMenuItem.Enabled =
!((Emulation.Consoles.GB.Gameboy)Global.Emulator).IsCGBMode();
}
}*/
//skipBIOSIntroToolStripMenuItem.Checked = Global.Config.GameBoySkipBIOS;
forceDMGModeToolStripMenuItem.Checked = Global.Config.GB_ForceDMG;

View File

@ -1731,6 +1731,12 @@ namespace BizHawk.MultiClient
if (Global.Config.GB_MulticartCompat) game.AddOption("MulitcartCompat");
Emulation.Consoles.GB.Gameboy gb = new Emulation.Consoles.GB.Gameboy(game, rom.FileData);
nextEmulator = gb;
if (gb.IsCGBMode())
{
gb.SetCGBColors(Global.Config.CGBColors);
}
else
{
try
{
using (StreamReader f = new StreamReader(Global.Config.GB_PaletteFile))
@ -1742,6 +1748,7 @@ namespace BizHawk.MultiClient
}
catch { }
}
}
else
{
// todo: get these bioses into a gamedb?? then we could demand different filenames for different regions?
@ -4242,7 +4249,18 @@ namespace BizHawk.MultiClient
{
if (Global.Emulator is Gameboy)
{
GBtools.ColorChooserForm.DoColorChooserFormDialog(((Gameboy)Global.Emulator).ChangeDMGColors, this);
var g = Global.Emulator as Gameboy;
if (g.IsCGBMode())
{
if (GBtools.CGBColorChooserForm.DoCGBColorChooserFormDialog(this))
{
g.SetCGBColors(Global.Config.CGBColors);
}
}
else
{
GBtools.ColorChooserForm.DoColorChooserFormDialog(g.ChangeDMGColors, this);
}
}
}

View File

@ -33,6 +33,7 @@ void LCD::setDmgPalette(unsigned long *const palette, const unsigned long *const
void LCD::setCgbPalette(unsigned *lut) {
for (int i = 0; i < 32768; i++)
cgbColorsRgb32[i] = lut[i];
refreshPalettes();
}
unsigned long LCD::gbcToRgb32(const unsigned bgr15) {