GB: Added options to emulate LCD blending and GBC LCD colors

This commit is contained in:
Sour 2020-06-20 23:20:03 -04:00
parent 084bb70402
commit ef930104e6
9 changed files with 124 additions and 26 deletions

View file

@ -434,8 +434,10 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
if(_cart->GetCoprocessor() == nullptr && _cart->GetGameboy()) {
_cart->GetGameboy()->PowerOn();
_consoleType = _cart->GetGameboy()->IsCgb() ? ConsoleType::GameboyColor : ConsoleType::Gameboy;
_settings->SetFlag(EmulationFlags::GameboyMode);
} else {
_consoleType = ConsoleType::Snes;
_settings->ClearFlag(EmulationFlags::GameboyMode);
}
@ -506,6 +508,11 @@ ConsoleRegion Console::GetRegion()
return _region;
}
ConsoleType Console::GetConsoleType()
{
return _consoleType;
}
void Console::UpdateRegion()
{
switch(_settings->GetEmulationConfig().Region) {

View file

@ -37,6 +37,7 @@ enum class MemoryOperationType;
enum class SnesMemoryType;
enum class EventType;
enum class ConsoleRegion;
enum class ConsoleType;
class Console : public std::enable_shared_from_this<Console>
{
@ -82,6 +83,7 @@ private:
atomic<bool> _threadPaused;
ConsoleRegion _region;
ConsoleType _consoleType;
uint32_t _masterClockRate;
atomic<bool> _isRunAheadFrame;
@ -130,6 +132,7 @@ public:
uint64_t GetMasterClock();
uint32_t GetMasterClockRate();
ConsoleRegion GetRegion();
ConsoleType GetConsoleType();
ConsoleLock AcquireLock();
void Lock();

View file

@ -11,6 +11,8 @@ const static double PI = 3.14159265358979323846;
DefaultVideoFilter::DefaultVideoFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
{
InitLookupTable();
_prevFrame = new uint16_t[256 * 240];
memset(_prevFrame, 0, 256 * 240 * sizeof(uint16_t));
}
void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturationShift)
@ -41,10 +43,26 @@ void DefaultVideoFilter::InitLookupTable()
double y, i, q;
for(int rgb555 = 0; rgb555 < 0x8000; rgb555++) {
uint8_t r = rgb555 & 0x1F;
uint8_t g = (rgb555 >> 5) & 0x1F;
uint8_t b = (rgb555 >> 10) & 0x1F;
if(_gbcAdjustColors) {
uint8_t r2 = std::min(240, (r * 26 + g * 4 + b * 2) >> 2);
uint8_t g2 = std::min(240, (g * 24 + b * 8) >> 2);
uint8_t b2 = std::min(240, (r * 6 + g * 4 + b * 22) >> 2);
r = r2;
g = g2;
b = b2;
} else {
r = To8Bit(r);
g = To8Bit(g);
b = To8Bit(b);
}
if(config.Hue != 0 || config.Saturation != 0 || config.Brightness != 0 || config.Contrast != 0) {
double redChannel = To8Bit(rgb555 & 0x1F) / 255.0;
double greenChannel = To8Bit((rgb555 >> 5) & 0x1F) / 255.0;
double blueChannel = To8Bit(rgb555 >> 10) / 255.0;
double redChannel = r / 255.0;
double greenChannel = g / 255.0;
double blueChannel = b / 255.0;
//Apply brightness, contrast, hue & saturation
RgbToYiq(redChannel, greenChannel, blueChannel, y, i, q);
@ -57,9 +75,6 @@ void DefaultVideoFilter::InitLookupTable()
int b = std::min(255, (int)(blueChannel * 255));
_calculatedPalette[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b;
} else {
uint8_t r = To8Bit(rgb555 & 0x1F);
uint8_t g = To8Bit((rgb555 >> 5) & 0x1F);
uint8_t b = To8Bit((rgb555 >> 10) & 0x1F);
_calculatedPalette[rgb555] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
@ -70,9 +85,15 @@ void DefaultVideoFilter::InitLookupTable()
void DefaultVideoFilter::OnBeforeApplyFilter()
{
VideoConfig config = _console->GetSettings()->GetVideoConfig();
if(_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config.Contrast || _videoConfig.Brightness != config.Brightness) {
EmulationConfig emulationConfig = _console->GetSettings()->GetEmulationConfig();
ConsoleType consoleType = _console->GetConsoleType();
bool adjustColors = emulationConfig.GbcAdjustColors && consoleType == ConsoleType::GameboyColor;
if(_videoConfig.Hue != config.Hue || _videoConfig.Saturation != config.Saturation || _videoConfig.Contrast != config.Contrast || _videoConfig.Brightness != config.Brightness || _gbcAdjustColors != adjustColors) {
_gbcAdjustColors = adjustColors;
InitLookupTable();
}
_gbBlendFrames = emulationConfig.GbBlendFrames && (consoleType == ConsoleType::Gameboy || consoleType == ConsoleType::GameboyColor);
_videoConfig = config;
}
@ -106,12 +127,12 @@ void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
for(uint32_t i = 0; i < frameInfo.Height; i++) {
if(i & 0x01) {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = ApplyScanlineEffect(_calculatedPalette[ppuOutputBuffer[i * width + j + yOffset + xOffset]], scanlineIntensity);
*out = ApplyScanlineEffect(GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset), scanlineIntensity);
out++;
}
} else {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
*out = _calculatedPalette[ppuOutputBuffer[i * width + j + yOffset + xOffset]];
*out = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset);
out++;
}
}
@ -119,7 +140,7 @@ void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
} else {
for(uint32_t i = 0; i < frameInfo.Height; i++) {
for(uint32_t j = 0; j < frameInfo.Width; j++) {
out[i*frameInfo.Width+j] = _calculatedPalette[ppuOutputBuffer[i * width + j + yOffset + xOffset]];
out[i*frameInfo.Width+j] = GetPixel(ppuOutputBuffer, i * width + j + yOffset + xOffset);
}
}
}
@ -136,6 +157,19 @@ void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
}
}
}
if(_gbBlendFrames) {
std::copy(ppuOutputBuffer, ppuOutputBuffer + 256 * 240, _prevFrame);
}
}
uint32_t DefaultVideoFilter::GetPixel(uint16_t* ppuFrame, uint32_t offset)
{
if(_gbBlendFrames) {
return BlendPixels(_calculatedPalette[_prevFrame[offset]], _calculatedPalette[ppuFrame[offset]]);
} else {
return _calculatedPalette[ppuFrame[offset]];
}
}
uint32_t DefaultVideoFilter::BlendPixels(uint32_t a, uint32_t b)

View file

@ -7,9 +7,13 @@
class DefaultVideoFilter : public BaseVideoFilter
{
private:
uint32_t _calculatedPalette[0x8000];
double _yiqToRgbMatrix[6];
VideoConfig _videoConfig;
uint32_t _calculatedPalette[0x8000] = {};
double _yiqToRgbMatrix[6] = {};
VideoConfig _videoConfig = {};
uint16_t* _prevFrame = nullptr;
bool _gbBlendFrames = false;
bool _gbcAdjustColors = false;
void InitConversionMatrix(double hueShift, double saturationShift);
void InitLookupTable();
@ -18,6 +22,7 @@ private:
void YiqToRgb(double y, double i, double q, double &r, double &g, double &b);
__forceinline static uint8_t To8Bit(uint8_t color);
__forceinline static uint32_t BlendPixels(uint32_t a, uint32_t b);
__forceinline uint32_t GetPixel(uint16_t* ppuFrame, uint32_t offset);
protected:
void OnBeforeApplyFilter();

View file

@ -270,6 +270,13 @@ enum class ConsoleRegion
Pal = 2
};
enum class ConsoleType
{
Snes = 0,
Gameboy = 1,
GameboyColor = 2
};
enum class GameboyModel
{
Auto = 0,
@ -301,6 +308,8 @@ struct EmulationConfig
GameboyModel GbModel = GameboyModel::Auto;
bool UseSgb2 = true;
bool GbBlendFrames = true;
bool GbcAdjustColors = true;
};
struct PreferencesConfig

View file

@ -31,6 +31,8 @@ namespace Mesen.GUI.Config
public GameboyModel GbModel = GameboyModel.Auto;
[MarshalAs(UnmanagedType.I1)] public bool UseSgb2 = true;
[MarshalAs(UnmanagedType.I1)] public bool GbBlendFrames = true;
[MarshalAs(UnmanagedType.I1)] public bool GbcAdjustColors = true;
public void ApplyConfig()
{

View file

@ -293,6 +293,12 @@
<Control ID="chkShowLagCounter">Show Lag Counter</Control>
<Control ID="btnResetLagCounter">Reset Counter</Control>
<Control ID="tpgGameboy">Game Boy</Control>
<Control ID="lblGameboy">Game Boy Model</Control>
<Control ID="chkUseSgb2">Use Super Game Boy 2 timings and behavior</Control>
<Control ID="chkGbBlendFrames">Enable LCD frame blending</Control>
<Control ID="chkGbcAdjustColors">Enable GBC LCD color emulation</Control>
<Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Cancel</Control>
</Form>

View file

@ -53,6 +53,9 @@
this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel();
this.lblGameboy = new System.Windows.Forms.Label();
this.cboGameboyModel = new System.Windows.Forms.ComboBox();
this.chkUseSgb2 = new System.Windows.Forms.CheckBox();
this.chkGbBlendFrames = new System.Windows.Forms.CheckBox();
this.chkGbcAdjustColors = new System.Windows.Forms.CheckBox();
this.tpgBsx = new System.Windows.Forms.TabPage();
this.grpBsxDateTime = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel();
@ -79,7 +82,6 @@
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.nudGsuClockSpeed = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblGsuClockSpeed = new System.Windows.Forms.Label();
this.chkUseSgb2 = new System.Windows.Forms.CheckBox();
this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
@ -452,10 +454,14 @@
this.tableLayoutPanel7.Controls.Add(this.lblGameboy, 0, 0);
this.tableLayoutPanel7.Controls.Add(this.cboGameboyModel, 1, 0);
this.tableLayoutPanel7.Controls.Add(this.chkUseSgb2, 0, 1);
this.tableLayoutPanel7.Controls.Add(this.chkGbBlendFrames, 0, 2);
this.tableLayoutPanel7.Controls.Add(this.chkGbcAdjustColors, 0, 3);
this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel7.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel7.Name = "tableLayoutPanel7";
this.tableLayoutPanel7.RowCount = 3;
this.tableLayoutPanel7.RowCount = 5;
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
@ -480,6 +486,39 @@
this.cboGameboyModel.Size = new System.Drawing.Size(119, 21);
this.cboGameboyModel.TabIndex = 1;
//
// chkUseSgb2
//
this.chkUseSgb2.AutoSize = true;
this.tableLayoutPanel7.SetColumnSpan(this.chkUseSgb2, 2);
this.chkUseSgb2.Location = new System.Drawing.Point(3, 30);
this.chkUseSgb2.Name = "chkUseSgb2";
this.chkUseSgb2.Size = new System.Drawing.Size(237, 17);
this.chkUseSgb2.TabIndex = 2;
this.chkUseSgb2.Text = "Use Super Game Boy 2 timings and behavior";
this.chkUseSgb2.UseVisualStyleBackColor = true;
//
// chkGbBlendFrames
//
this.chkGbBlendFrames.AutoSize = true;
this.tableLayoutPanel7.SetColumnSpan(this.chkGbBlendFrames, 2);
this.chkGbBlendFrames.Location = new System.Drawing.Point(3, 53);
this.chkGbBlendFrames.Name = "chkGbBlendFrames";
this.chkGbBlendFrames.Size = new System.Drawing.Size(155, 17);
this.chkGbBlendFrames.TabIndex = 3;
this.chkGbBlendFrames.Text = "Enable LCD frame blending";
this.chkGbBlendFrames.UseVisualStyleBackColor = true;
//
// chkGbcAdjustColors
//
this.chkGbcAdjustColors.AutoSize = true;
this.tableLayoutPanel7.SetColumnSpan(this.chkGbcAdjustColors, 2);
this.chkGbcAdjustColors.Location = new System.Drawing.Point(3, 76);
this.chkGbcAdjustColors.Name = "chkGbcAdjustColors";
this.chkGbcAdjustColors.Size = new System.Drawing.Size(182, 17);
this.chkGbcAdjustColors.TabIndex = 4;
this.chkGbcAdjustColors.Text = "Enable GBC LCD color emulation";
this.chkGbcAdjustColors.UseVisualStyleBackColor = true;
//
// tpgBsx
//
this.tpgBsx.Controls.Add(this.grpBsxDateTime);
@ -869,17 +908,6 @@
this.lblGsuClockSpeed.TabIndex = 0;
this.lblGsuClockSpeed.Text = "Super FX clock speed (%):";
//
// chkUseSgb2
//
this.chkUseSgb2.AutoSize = true;
this.tableLayoutPanel7.SetColumnSpan(this.chkUseSgb2, 2);
this.chkUseSgb2.Location = new System.Drawing.Point(3, 30);
this.chkUseSgb2.Name = "chkUseSgb2";
this.chkUseSgb2.Size = new System.Drawing.Size(237, 17);
this.chkUseSgb2.TabIndex = 2;
this.chkUseSgb2.Text = "Use Super Game Boy 2 timings and behavior";
this.chkUseSgb2.UseVisualStyleBackColor = true;
//
// frmEmulationConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -985,5 +1013,7 @@
private System.Windows.Forms.Label lblGameboy;
private System.Windows.Forms.ComboBox cboGameboyModel;
private System.Windows.Forms.CheckBox chkUseSgb2;
private System.Windows.Forms.CheckBox chkGbBlendFrames;
private System.Windows.Forms.CheckBox chkGbcAdjustColors;
}
}

View file

@ -40,6 +40,8 @@ namespace Mesen.GUI.Forms.Config
AddBinding(nameof(EmulationConfig.GbModel), cboGameboyModel);
AddBinding(nameof(EmulationConfig.UseSgb2), chkUseSgb2);
AddBinding(nameof(EmulationConfig.GbBlendFrames), chkGbBlendFrames);
AddBinding(nameof(EmulationConfig.GbcAdjustColors), chkGbcAdjustColors);
long customDate = ConfigManager.Config.Emulation.BsxCustomDate;
if(customDate >= 0) {