GB: Added options to emulate LCD blending and GBC LCD colors
This commit is contained in:
parent
084bb70402
commit
ef930104e6
9 changed files with 124 additions and 26 deletions
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
56
UI/Forms/Config/frmEmulationConfig.Designer.cs
generated
56
UI/Forms/Config/frmEmulationConfig.Designer.cs
generated
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue