Add option to mute sound during speedup

Add core option to mute sound during speedup, implemented in the gba
core. Link the option to the SDL port as well.

Add the new Mute Sound option as a checkbox to the xrc for the
Speedup/Turbo dialog and improve the dialog appearance.

Fix the max values for the options speedup_throttle and
speedup_frame_skip.

Add base class for numeric OptionProxy types implementing the +=, -=
operators, increment/decrement operators and operator T(). Add tests for
these operators on numeric types.

Move Speedup/Turbo dialog code from guiinit.cpp to a dialog class and
rewrite it using validators.

Remove the "GL VIEWPORT" debug prints from panel.cpp.

Fix #865

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
This commit is contained in:
Rafael Kitover 2024-07-01 20:09:35 +00:00
parent 7a0826a60c
commit e2cf6ecba6
13 changed files with 423 additions and 170 deletions

View File

@ -59,6 +59,7 @@ extern struct CoreOptions {
bool speedHack = false;
bool speedup = false;
bool speedup_throttle_frame_skip = false;
bool speedup_mute = true;
int cheatsEnabled = 1;
int cpuDisableSfx = 0;
int cpuSaveType = 0;

View File

@ -3845,6 +3845,8 @@ void CPULoop(int ticks)
bool turbo_button_pressed = (joy >> 10) & 1;
#ifndef __LIBRETRO__
static uint32_t last_throttle;
static bool current_volume_saved = false;
static float current_volume;
if (turbo_button_pressed) {
if (coreOptions.speedup_frame_skip)
@ -3859,10 +3861,23 @@ void CPULoop(int ticks)
if (coreOptions.speedup_throttle_frame_skip)
framesToSkip += static_cast<int>(std::ceil(double(coreOptions.speedup_throttle) / 100.0) - 1);
}
if (coreOptions.speedup_mute && !current_volume_saved) {
current_volume = soundGetVolume();
current_volume_saved = true;
soundSetVolume(0);
}
}
else if (speedup_throttle_set) {
soundSetThrottle(DowncastU16(last_throttle));
speedup_throttle_set = false;
else {
if (current_volume_saved) {
soundSetVolume(current_volume);
current_volume_saved = false;
}
if (speedup_throttle_set) {
soundSetThrottle(DowncastU16(last_throttle));
speedup_throttle_set = false;
}
}
#else
if (turbo_button_pressed)

View File

@ -98,7 +98,8 @@ enum named_opts
OPT_SOUND_FILTERING,
OPT_SPEEDUP_THROTTLE,
OPT_SPEEDUP_FRAME_SKIP,
OPT_NO_SPEEDUP_THROTTLE_FRAME_SKIP
OPT_NO_SPEEDUP_THROTTLE_FRAME_SKIP,
OPT_NO_SPEEDUP_MUTE
};
#define SOUND_MAX_VOLUME 2.0
@ -232,6 +233,7 @@ struct option argOptions[] = {
{ "speedup-throttle", required_argument, 0, OPT_SPEEDUP_THROTTLE },
{ "speedup-frame-skip", required_argument, 0, OPT_SPEEDUP_FRAME_SKIP },
{ "no-speedup-throttle-frame-skip", no_argument, 0, OPT_NO_SPEEDUP_THROTTLE_FRAME_SKIP },
{ "no-speedup-mute", no_argument, 0, OPT_NO_SPEEDUP_MUTE },
{ "use-bios", no_argument, &coreOptions.useBios, 1 },
{ "verbose", required_argument, 0, 'v' },
{ "win-gb-printer-enabled", no_argument, &coreOptions.winGbPrinterEnabled, 1 },
@ -347,6 +349,7 @@ void LoadConfig()
coreOptions.speedup_throttle = ReadPref("speedupThrottle", 100);
coreOptions.speedup_frame_skip = ReadPref("speedupFrameSkip", 9);
coreOptions.speedup_throttle_frame_skip = ReadPref("speedupThrottleFrameSkip", 0);
coreOptions.speedup_mute = ReadPref("speedupMute", 1);
coreOptions.useBios = ReadPrefHex("useBiosGBA");
coreOptions.winGbPrinterEnabled = ReadPref("gbPrinter", 0);
@ -990,6 +993,9 @@ int ReadOpts(int argc, char ** argv)
case OPT_NO_SPEEDUP_THROTTLE_FRAME_SKIP:
coreOptions.speedup_throttle_frame_skip = false;
break;
case OPT_NO_SPEEDUP_MUTE:
coreOptions.speedup_mute = false;
break;
}
}
return op;

View File

@ -31,6 +31,8 @@ set(VBAM_WX_COMMON
dialogs/joypad-config.h
dialogs/sound-config.cpp
dialogs/sound-config.h
dialogs/speedup-config.cpp
dialogs/speedup-config.h
drawing.h
extra-translations.cpp
gfxviewers.cpp

View File

@ -328,9 +328,10 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kPrefSkipSaveGameCheats, &coreOptions.skipSaveGameCheats, 0, 1),
Option(OptionID::kPrefSkipSaveGameBattery, &coreOptions.skipSaveGameBattery, 0, 1),
Option(OptionID::kPrefThrottle, &coreOptions.throttle, 0, 450),
Option(OptionID::kPrefSpeedupThrottle, &coreOptions.speedup_throttle, 0, 3000),
Option(OptionID::kPrefSpeedupFrameSkip, &coreOptions.speedup_frame_skip, 0, 300),
Option(OptionID::kPrefSpeedupThrottle, &coreOptions.speedup_throttle, 0, 450),
Option(OptionID::kPrefSpeedupFrameSkip, &coreOptions.speedup_frame_skip, 0, 40),
Option(OptionID::kPrefSpeedupThrottleFrameSkip, &coreOptions.speedup_throttle_frame_skip),
Option(OptionID::kPrefSpeedupMute, &coreOptions.speedup_mute),
Option(OptionID::kPrefUseBiosGB, &g_owned_opts.use_bios_file_gb),
Option(OptionID::kPrefUseBiosGBA, &g_owned_opts.use_bios_file_gba),
Option(OptionID::kPrefUseBiosGBC, &g_owned_opts.use_bios_file_gbc),
@ -531,6 +532,8 @@ const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
"throttle)")},
OptionData{"preferences/speedupThrottleFrameSkip", "",
_("Use frame skip for speedup throttle")},
OptionData{"preferences/speedupMute", "",
_("Mute sound during speedup")},
OptionData{"preferences/useBiosGB", "BootRomGB", _("Use the specified BIOS file for Game Boy")},
OptionData{"preferences/useBiosGBA", "BootRomEn", _("Use the specified BIOS file")},
OptionData{"preferences/useBiosGBC", "BootRomGBC",

View File

@ -99,6 +99,7 @@ enum class OptionID {
kPrefSpeedupThrottle,
kPrefSpeedupFrameSkip,
kPrefSpeedupThrottleFrameSkip,
kPrefSpeedupMute,
kPrefUseBiosGB,
kPrefUseBiosGBA,
kPrefUseBiosGBC,

View File

@ -103,6 +103,7 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
/*kPrefSpeedupThrottle*/ Option::Type::kUnsigned,
/*kPrefSpeedupFrameSkip*/ Option::Type::kUnsigned,
/*kPrefSpeedupThrottleFrameSkip*/ Option::Type::kBool,
/*kPrefSpeedupMute*/ Option::Type::kBool,
/*kPrefUseBiosGB*/ Option::Type::kBool,
/*kPrefUseBiosGBA*/ Option::Type::kBool,
/*kPrefUseBiosGBC*/ Option::Type::kBool,
@ -174,11 +175,43 @@ private:
Option* option_;
};
template <typename T>
class OptionProxyNumeric {
public:
virtual T Get() const = 0;
virtual bool Set(T value) = 0;
virtual T Min() const = 0;
virtual T Max() const = 0;
bool operator++() { return *this += 1; }
bool operator--() { return *this -= 1; }
bool operator++(int) { return *this += 1; }
bool operator--(int) { return *this -= 1; }
bool operator+=(T value) {
const int new_value = Get() + value;
if (new_value > Max()) {
return Set(Max());
} else {
return Set(new_value);
}
}
bool operator-=(T value) {
const int new_value = Get() - value;
if (new_value < Min()) {
return Set(Min());
} else {
return Set(new_value);
}
}
operator T() const { return Get(); }
};
template <OptionID ID>
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kDouble>::type> {
Option::Type::kDouble>::type> : public OptionProxyNumeric<double> {
public:
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
@ -187,9 +220,7 @@ public:
bool Set(double value) { return option_->SetDouble(value); }
double Min() const { return option_->GetDoubleMin(); }
double Max() const { return option_->GetDoubleMax(); }
bool operator=(double value) { return Set(value); }
operator double() const { return Get(); }
private:
Option* option_;
@ -199,7 +230,7 @@ template <OptionID ID>
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kInt>::type> {
Option::Type::kInt>::type> : public OptionProxyNumeric<int32_t> {
public:
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
@ -208,25 +239,7 @@ public:
bool Set(int32_t value) { return option_->SetInt(value); }
int32_t Min() const { return option_->GetIntMin(); }
int32_t Max() const { return option_->GetIntMax(); }
bool operator=(int32_t value) { return Set(value); }
bool operator+=(int32_t value) {
const int new_value = Get() + value;
if (new_value > Max()) {
return Set(Max());
} else {
return Set(new_value);
}
}
bool operator-=(int32_t value) {
const int new_value = Get() - value;
if (new_value < Min()) {
return Set(Min());
} else {
return Set(new_value);
}
}
operator int32_t() const { return Get(); }
private:
Option* option_;
@ -236,7 +249,7 @@ template <OptionID ID>
class OptionProxy<
ID,
typename std::enable_if<kOptionsTypes[static_cast<size_t>(ID)] ==
Option::Type::kUnsigned>::type> {
Option::Type::kUnsigned>::type> : public OptionProxyNumeric<uint32_t> {
public:
OptionProxy() : option_(Option::ByID(ID)) {}
~OptionProxy() = default;
@ -245,9 +258,7 @@ public:
bool Set(uint32_t value) { return option_->SetUnsigned(value); }
uint32_t Min() const { return option_->GetUnsignedMin(); }
uint32_t Max() const { return option_->GetUnsignedMax(); }
bool operator=(int32_t value) { return Set(value); }
operator int32_t() const { return Get(); }
bool operator=(uint32_t value) { return Set(value); }
private:
Option* option_;

View File

@ -353,3 +353,109 @@ TEST(OptionProxyTest, MatchingTypes) {
EXPECT_EQ(option->type(), proxy_type);
}
}
TEST(OptionProxyTest, NumericOperators) {
wxLogNull disable_logging;
int32_t int_opt = OPTION(kDispMaxThreads);
int_opt++;
OPTION(kDispMaxThreads)++;
EXPECT_EQ(int_opt, OPTION(kDispMaxThreads));
int_opt--;
OPTION(kDispMaxThreads)--;
EXPECT_EQ(int_opt, OPTION(kDispMaxThreads));
++int_opt;
OPTION(kDispMaxThreads)++;
EXPECT_EQ(int_opt, OPTION(kDispMaxThreads));
--int_opt;
OPTION(kDispMaxThreads)--;
EXPECT_EQ(int_opt, OPTION(kDispMaxThreads));
int_opt += 2;
OPTION(kDispMaxThreads) += 2;
EXPECT_EQ(int_opt, OPTION(kDispMaxThreads));
int_opt -= 2;
OPTION(kDispMaxThreads) -= 2;
EXPECT_EQ(int_opt, OPTION(kDispMaxThreads));
OPTION(kDispMaxThreads) = OPTION(kDispMaxThreads).Max();
OPTION(kDispMaxThreads)++;
EXPECT_EQ(OPTION(kDispMaxThreads), OPTION(kDispMaxThreads).Max());
OPTION(kDispMaxThreads) = OPTION(kDispMaxThreads).Min();
OPTION(kDispMaxThreads)--;
EXPECT_EQ(OPTION(kDispMaxThreads), OPTION(kDispMaxThreads).Min());
uint32_t unsigned_opt = OPTION(kJoyDefault);
unsigned_opt++;
OPTION(kJoyDefault)++;
EXPECT_EQ(unsigned_opt, OPTION(kJoyDefault));
unsigned_opt--;
OPTION(kJoyDefault)--;
EXPECT_EQ(unsigned_opt, OPTION(kJoyDefault));
++unsigned_opt;
OPTION(kJoyDefault)++;
EXPECT_EQ(unsigned_opt, OPTION(kJoyDefault));
--unsigned_opt;
OPTION(kJoyDefault)--;
EXPECT_EQ(unsigned_opt, OPTION(kJoyDefault));
unsigned_opt += 2;
OPTION(kJoyDefault) += 2;
EXPECT_EQ(unsigned_opt, OPTION(kJoyDefault));
unsigned_opt -= 2;
OPTION(kJoyDefault) -= 2;
EXPECT_EQ(unsigned_opt, OPTION(kJoyDefault));
OPTION(kJoyDefault) = OPTION(kJoyDefault).Max();
OPTION(kJoyDefault)++;
EXPECT_EQ(OPTION(kJoyDefault), OPTION(kJoyDefault).Max());
OPTION(kJoyDefault) = OPTION(kJoyDefault).Min();
OPTION(kJoyDefault)--;
EXPECT_EQ(OPTION(kJoyDefault), OPTION(kJoyDefault).Min());
double double_opt = OPTION(kDispScale);
double_opt++;
OPTION(kDispScale)++;
EXPECT_EQ(double_opt, OPTION(kDispScale));
double_opt--;
OPTION(kDispScale)--;
EXPECT_EQ(double_opt, OPTION(kDispScale));
++double_opt;
OPTION(kDispScale)++;
EXPECT_EQ(double_opt, OPTION(kDispScale));
--double_opt;
OPTION(kDispScale)--;
EXPECT_EQ(double_opt, OPTION(kDispScale));
double_opt += 2;
OPTION(kDispScale) += 2;
EXPECT_EQ(double_opt, OPTION(kDispScale));
double_opt -= 2;
OPTION(kDispScale) -= 2;
EXPECT_EQ(double_opt, OPTION(kDispScale));
OPTION(kDispScale) = OPTION(kDispScale).Max();
OPTION(kDispScale)++;
EXPECT_EQ(OPTION(kDispScale), OPTION(kDispScale).Max());
OPTION(kDispScale) = OPTION(kDispScale).Min();
OPTION(kDispScale)--;
EXPECT_EQ(OPTION(kDispScale), OPTION(kDispScale).Min());
}

View File

@ -0,0 +1,154 @@
#include "wx/dialogs/speedup-config.h"
#include <wx/checkbox.h>
#include <wx/spinctrl.h>
#include <wx/xrc/xmlres.h>
#include "core/base/check.h"
#include "wx/config/option-proxy.h"
#include "wx/dialogs/base-dialog.h"
#include "wx/widgets/option-validator.h"
// This dialog has a spin control representing the speedup value as it feels
// like to the user. Values below 450 can be an actual throttle or a number of
// frames to skip depending on whether the Frame Skip checkbox is checked. The
// number of frames is the spin control value divided by 100, for example 300
// with the Frame Skip checkbox checked means 3 frames to skip. Values above 450
// are always the number of frames to skip, for example 900 means 9 frames to skip.
//
// The config option SpeedupThrottle is the throttle value, if frame skip is
// used it is 0. The config option SpeedupFrameSkip is the number of frames to
// skip, if throttle is used it is 0. The config option SpeedupThrottleFrameSkip
// represents the Frame Skip checkbox for values under 450, that is if they are
// interpreted as a frame skip or a throttle.
namespace dialogs {
bool SpeedupConfigValidator::TransferToWindow() {
uint32_t opt_frame_skip = OPTION(kPrefSpeedupFrameSkip);
uint32_t opt_throttle = OPTION(kPrefSpeedupThrottle);
bool opt_throttle_frame_skip = OPTION(kPrefSpeedupThrottleFrameSkip);
auto dialog = static_cast<SpeedupConfig*>(GetWindow());
dialog->prev_frame_skip_cb_ = opt_throttle_frame_skip;
if (opt_frame_skip != 0) {
dialog->speedup_throttle_spin_->SetValue(opt_frame_skip * 100);
dialog->prev_throttle_spin_ = opt_frame_skip * 100;
dialog->frame_skip_cb_->SetValue(true);
dialog->frame_skip_cb_->Disable();
} else {
dialog->speedup_throttle_spin_->SetValue(opt_throttle);
dialog->prev_throttle_spin_ = opt_throttle;
dialog->frame_skip_cb_->SetValue(opt_throttle_frame_skip);
if (opt_throttle != 0)
dialog->frame_skip_cb_->Enable();
else
dialog->frame_skip_cb_->Disable();
}
return true;
}
bool SpeedupConfigValidator::TransferFromWindow() {
auto dialog = static_cast<SpeedupConfig*>(GetWindow());
uint32_t val = dialog->speedup_throttle_spin_->GetValue();
VBAM_CHECK(val >= 0);
if (val == 0) {
OPTION(kPrefSpeedupThrottle) = 0;
OPTION(kPrefSpeedupFrameSkip) = 0;
OPTION(kPrefSpeedupThrottleFrameSkip) = false;
} else if (val <= OPTION(kPrefSpeedupThrottle).Max()) {
OPTION(kPrefSpeedupThrottle) = val;
OPTION(kPrefSpeedupFrameSkip) = 0;
OPTION(kPrefSpeedupThrottleFrameSkip) = dialog->frame_skip_cb_->GetValue();
} else { // val > throttle_max
OPTION(kPrefSpeedupThrottle) = 100;
OPTION(kPrefSpeedupFrameSkip) = val / 100;
OPTION(kPrefSpeedupThrottleFrameSkip) = false;
}
return true;
}
// static
SpeedupConfig* SpeedupConfig::NewInstance(wxWindow* parent) {
VBAM_CHECK(parent);
return new SpeedupConfig(parent);
}
SpeedupConfig::SpeedupConfig(wxWindow* parent)
: BaseDialog(parent, "SpeedupConfig") {
speedup_throttle_spin_ = GetValidatedChild<wxSpinCtrl>("SpeedupThrottleSpin");
frame_skip_cb_ = GetValidatedChild<wxCheckBox>("SpeedupThrottleFrameSkip");
speedup_throttle_spin_->SetRange(OPTION(kPrefSpeedupThrottle).Min(), OPTION(kPrefSpeedupFrameSkip).Max() * 100);
speedup_throttle_spin_->SetWindowStyle(wxSP_ARROW_KEYS);
#ifdef wxTE_PROCESS_ENTER
speedup_throttle_spin_->SetWindowStyleFlag(wxTE_PROCESS_ENTER);
#endif
GetValidatedChild<wxCheckBox>("SpeedupMute")->SetValidator(widgets::OptionBoolValidator(config::OptionID::kPrefSpeedupMute));
using namespace std::placeholders;
Bind(wxEVT_SPIN_UP, std::bind(&SpeedupConfig::SetSpeedupThrottle, this, _1), XRCID("SpeedupThrottleSpin"));
Bind(wxEVT_SPIN_DOWN, std::bind(&SpeedupConfig::SetSpeedupThrottle, this, _1), XRCID("SpeedupThrottleSpin"));
Bind(wxEVT_SPIN, std::bind(&SpeedupConfig::SetSpeedupThrottle, this, _1), XRCID("SpeedupThrottleSpin"));
Bind(wxEVT_TEXT, std::bind(&SpeedupConfig::SetSpeedupThrottle, this, _1), XRCID("SpeedupThrottleSpin"));
Bind(wxEVT_CHECKBOX, std::bind(&SpeedupConfig::ToggleSpeedupFrameSkip, this), XRCID("SpeedupThrottleFrameSkip"));
SetValidator(SpeedupConfigValidator());
Fit();
}
void SpeedupConfig::SetSpeedupThrottle(wxCommandEvent& evt)
{
VBAM_CHECK(evt.GetEventObject() == speedup_throttle_spin_);
uint32_t val = speedup_throttle_spin_->GetValue();
VBAM_CHECK(val >= 0);
if (val == 0) {
frame_skip_cb_->SetValue(false);
frame_skip_cb_->Disable();
} else if (val <= OPTION(kPrefSpeedupThrottle).Max()) {
frame_skip_cb_->SetValue(prev_frame_skip_cb_);
frame_skip_cb_->Enable();
} else { // val > throttle_max
if (val > prev_throttle_spin_)
val += 100;
val = std::floor((double)val / 100) * 100;
uint32_t max = speedup_throttle_spin_->GetMax();
if (val > max)
val = max;
frame_skip_cb_->SetValue(true);
frame_skip_cb_->Disable();
}
speedup_throttle_spin_->SetValue(val);
prev_throttle_spin_ = val;
}
void SpeedupConfig::ToggleSpeedupFrameSkip()
{
prev_frame_skip_cb_ = frame_skip_cb_->GetValue();
}
} // namespace dialogs

View File

@ -0,0 +1,54 @@
#ifndef VBAM_WX_DIALOGS_SPEEDUP_CONFIG_H_
#define VBAM_WX_DIALOGS_SPEEDUP_CONFIG_H_
// Manages the Speedup/Turbo configuration dialog.
//
// See the explanation for the implementation in the .cpp file.
#include <wx/checkbox.h>
#include "wx/dialogs/base-dialog.h"
#include <wx/spinctrl.h>
#include <wx/validate.h>
namespace dialogs {
class SpeedupConfigValidator : public wxValidator {
public:
SpeedupConfigValidator() = default;
~SpeedupConfigValidator() override = default;
bool TransferToWindow() override;
bool TransferFromWindow() override;
bool Validate([[maybe_unused]]wxWindow* parent) override { return true; }
private:
wxObject* Clone() const override { return new SpeedupConfigValidator(); }
};
class SpeedupConfig : public BaseDialog {
public:
static SpeedupConfig* NewInstance(wxWindow* parent);
~SpeedupConfig() override = default;
void ToggleSpeedupFrameSkip();
void ToggleSpeedupMute();
void SetSpeedupThrottle(wxCommandEvent& evt);
private:
// The constructor is private so initialization has to be done via the
// static method. This is because this class is destroyed when its
// owner, `parent` is destroyed. This prevents accidental deletion.
SpeedupConfig(wxWindow* parent);
wxSpinCtrl* speedup_throttle_spin_;
wxCheckBox* frame_skip_cb_;
bool prev_frame_skip_cb_;
unsigned prev_throttle_spin_;
friend class SpeedupConfigValidator;
};
} // namespace dialogs
#endif // VBAM_WX_DIALOGS_SPEEDUP_CONFIG_H_

View File

@ -48,6 +48,7 @@
#include "wx/dialogs/gb-rom-info.h"
#include "wx/dialogs/joypad-config.h"
#include "wx/dialogs/sound-config.h"
#include "wx/dialogs/speedup-config.h"
#include "wx/opts.h"
#include "wx/widgets/checkedlistctrl.h"
#include "wx/widgets/option-validator.h"
@ -1483,92 +1484,6 @@ public:
}
} throttle_ctrl;
static class SpeedupThrottleCtrl_t : public wxEvtHandler {
public:
wxSpinCtrl* speedup_throttle_spin;
wxCheckBox* frame_skip_cb;
void SetSpeedupThrottle(wxCommandEvent& evt)
{
unsigned val = speedup_throttle_spin->GetValue();
evt.Skip(false);
if (val == 0) {
coreOptions.speedup_throttle = 0;
coreOptions.speedup_frame_skip = 0;
coreOptions.speedup_throttle_frame_skip = false;
frame_skip_cb->SetValue(false);
frame_skip_cb->Disable();
if (evt.GetEventType() == wxEVT_TEXT)
return; // Do not update value if user cleared text box.
}
else if (val <= 450) {
coreOptions.speedup_throttle = val;
coreOptions.speedup_frame_skip = 0;
frame_skip_cb->SetValue(prev_frame_skip_cb);
frame_skip_cb->Enable();
}
else { // val > 450
coreOptions.speedup_throttle = 100;
coreOptions.speedup_throttle_frame_skip = false;
unsigned rounded = std::round((double)val / 100) * 100;
coreOptions.speedup_frame_skip = rounded / 100 - 1;
// Round up or down to the nearest 100%.
// For example, when the up/down buttons are pressed on the spin
// control.
if ((int)(val - rounded) > 0)
coreOptions.speedup_frame_skip++;
else if ((int)(val - rounded) < 0)
coreOptions.speedup_frame_skip--;
frame_skip_cb->SetValue(true);
frame_skip_cb->Disable();
val = (coreOptions.speedup_frame_skip + 1) * 100;
}
speedup_throttle_spin->SetValue(val);
}
void SetSpeedupFrameSkip(wxCommandEvent& evt)
{
(void)evt; // Unused param.
bool checked = frame_skip_cb->GetValue();
coreOptions.speedup_throttle_frame_skip = prev_frame_skip_cb = checked;
}
void Init(wxShowEvent& ev)
{
if (coreOptions.speedup_frame_skip != 0) {
speedup_throttle_spin->SetValue((coreOptions.speedup_frame_skip + 1) * 100);
frame_skip_cb->SetValue(true);
frame_skip_cb->Disable();
}
else {
speedup_throttle_spin->SetValue(coreOptions.speedup_throttle);
frame_skip_cb->SetValue(coreOptions.speedup_throttle_frame_skip);
if (coreOptions.speedup_throttle != 0)
frame_skip_cb->Enable();
else
frame_skip_cb->Disable();
}
ev.Skip();
}
private:
bool prev_frame_skip_cb = coreOptions.speedup_throttle_frame_skip;
} speedup_throttle_ctrl;
/////////////////////////////
//Check if a pointer from the XRC file is valid. If it's not, throw an error telling the user.
template <typename T>
@ -2376,38 +2291,6 @@ bool MainFrame::BindControls()
d->Fit();
}
// SpeedUp Key Config
d = LoadXRCDialog("SpeedupConfig");
{
speedup_throttle_ctrl.frame_skip_cb = SafeXRCCTRL<wxCheckBox>(d, "SpeedupThrottleFrameSkip");
speedup_throttle_ctrl.speedup_throttle_spin = SafeXRCCTRL<wxSpinCtrl>(d, "SpeedupThrottleSpin");
speedup_throttle_ctrl.speedup_throttle_spin->Connect(wxEVT_SPIN_UP,
wxCommandEventHandler(SpeedupThrottleCtrl_t::SetSpeedupThrottle),
NULL, &speedup_throttle_ctrl);
speedup_throttle_ctrl.speedup_throttle_spin->Connect(wxEVT_SPIN_DOWN,
wxCommandEventHandler(SpeedupThrottleCtrl_t::SetSpeedupThrottle),
NULL, &speedup_throttle_ctrl);
speedup_throttle_ctrl.speedup_throttle_spin->Connect(wxEVT_SPIN,
wxCommandEventHandler(SpeedupThrottleCtrl_t::SetSpeedupThrottle),
NULL, &speedup_throttle_ctrl);
speedup_throttle_ctrl.speedup_throttle_spin->Connect(wxEVT_TEXT,
wxCommandEventHandler(SpeedupThrottleCtrl_t::SetSpeedupThrottle),
NULL, &speedup_throttle_ctrl);
speedup_throttle_ctrl.frame_skip_cb->Connect(wxEVT_CHECKBOX,
wxCommandEventHandler(SpeedupThrottleCtrl_t::SetSpeedupFrameSkip),
NULL, &speedup_throttle_ctrl);
d->Connect(wxEVT_SHOW, wxShowEventHandler(SpeedupThrottleCtrl_t::Init),
NULL, &speedup_throttle_ctrl);
d->Fit();
}
wxMenuItem* suspend_scr_saver_mi = XRCITEM("SuspendScreenSaver");
if (suspend_scr_saver_mi)
{
@ -2470,6 +2353,7 @@ bool MainFrame::BindControls()
dialogs::SoundConfig::NewInstance(this);
dialogs::DirectoriesConfig::NewInstance(this);
dialogs::JoypadConfig::NewInstance(this, std::bind(&wxvbamApp::bindings, &wxGetApp()));
dialogs::SpeedupConfig::NewInstance(this);
#ifndef NO_LINK
d = LoadXRCDialog("LinkConfig");

View File

@ -2368,13 +2368,6 @@ void GLDrawingPanel::AdjustViewport()
int x, y;
widgets::GetRealPixelClientSize(this, &x, &y);
glViewport(0, 0, x, y);
#ifdef DEBUG
// you can use this to check that the gl surface is indeed high res
GLint m_viewport[4];
glGetIntegerv(GL_VIEWPORT, m_viewport);
wxLogDebug(wxT("GL VIEWPORT: %d, %d, %d, %d"), m_viewport[0], m_viewport[1], m_viewport[2], m_viewport[3]);
#endif
}
void GLDrawingPanel::RefreshGL()

View File

@ -11,7 +11,7 @@
<weight>bold</weight>
</font>
</object>
<flag>wxALL</flag>
<flag>wxALL|wxALIGN_CENTRE_HORIZONTAL</flag>
<border>5</border>
</object>
<object class="sizeritem">
@ -32,9 +32,7 @@
</object>
<object class="sizeritem">
<object class="wxSpinCtrl" name="SpeedupThrottleSpin">
<value>0</value>
<min>0</min>
<max>4000</max>
<size>40,-1d</size>
</object>
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
<border>5</border>
@ -46,23 +44,48 @@
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxCheckBox" name="SpeedupThrottleFrameSkip">
<label>Frame skip</label>
<object class="wxFlexGridSizer">
<rows>1</rows>
<cols>2</cols>
<growablerows>0</growablerows>
<growablecols>0,1</growablecols>
<object class="sizeritem">
<object class="wxCheckBox" name="SpeedupThrottleFrameSkip">
<label>Frame skip</label>
</object>
<flag>wxALL</flag>
<border>5</border>
</object>
<object class="sizeritem">
<object class="wxCheckBox" name="SpeedupMute">
<label>Mute Sound</label>
</object>
<flag>wxALL</flag>
<border>5</border>
</object>
</object>
<flag>wxALL</flag>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
</object>
<object class="sizeritem">
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxStdDialogButtonSizer">
<object class="button">
<object class="wxFlexGridSizer">
<rows>1</rows>
<cols>2</cols>
<growablerows>0</growablerows>
<growablecols>0,1</growablecols>
<object class="sizeritem">
<object class="wxButton" name="wxID_OK"/>
<flag>wxALL</flag>
<border>10</border>
</object>
<object class="button">
<object class="sizeritem">
<object class="wxButton" name="wxID_CANCEL"/>
<flag>wxALL|wxALIGN_RIGHT</flag>
<border>10</border>
</object>
</object>
<flag>wxALL|wxEXPAND</flag>
<border>10</border>
</object>
</object>
</object>