Update to spice2x-23-06-08
This commit is contained in:
@@ -13,5 +13,6 @@ IDR_CHANGELOG RCDATA "../changelog.txt"
|
||||
IDR_LICENSES RCDATA "../licenses.txt"
|
||||
IDR_PATCHES RCDATA "../build/patches.json"
|
||||
IDR_README RCDATA "../readme.txt"
|
||||
IDR_DSEGFONT RCDATA "../external/dseg/DSEG14Classic-Italic.ttf"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,7 @@ cfg::ConfiguratorWindow::ConfiguratorWindow() {
|
||||
|
||||
// determine window title
|
||||
if (cfg::CONFIGURATOR_TYPE == cfg::ConfigType::Config) {
|
||||
WINDOW_TITLE = "SpiceTools Config (" + to_string(VERSION_STRING_CFG) + ")";
|
||||
WINDOW_TITLE = "spice2x config - a fork of SpiceTools (" + to_string(VERSION_STRING_CFG) + ")";
|
||||
WINDOW_SIZE_X = 800;
|
||||
WINDOW_SIZE_Y = 600;
|
||||
} else if (cfg::CONFIGURATOR_TYPE == cfg::ConfigType::KFControl) {
|
||||
@@ -49,6 +49,10 @@ cfg::ConfiguratorWindow::ConfiguratorWindow() {
|
||||
NULL,
|
||||
GetModuleHandle(NULL),
|
||||
(LPVOID) this);
|
||||
|
||||
if (this->hWnd) {
|
||||
overlay::USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT = true;
|
||||
}
|
||||
}
|
||||
|
||||
cfg::ConfiguratorWindow::~ConfiguratorWindow() {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
name="spicecfg.exe"
|
||||
type="win32"
|
||||
/>
|
||||
<description>SpiceTools Config</description>
|
||||
<description>spice2x config</description>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
|
||||
+18
-3
@@ -68,17 +68,32 @@ std::vector<std::string> Option::values_text() const {
|
||||
return values;
|
||||
}
|
||||
|
||||
int Option::value_int() const {
|
||||
uint32_t Option::value_uint32() const {
|
||||
if (this->definition.type != OptionType::Integer && this->definition.type != OptionType::Enum) {
|
||||
log_fatal("option", "value_int() called on {}/{}", this->definition.title, this->definition.type);
|
||||
log_fatal("option", "invalid call: value_uint32() called on {}/{}", this->definition.title, this->definition.type);
|
||||
return 0;
|
||||
}
|
||||
char *p;
|
||||
auto res = strtol(this->value.c_str(), &p, 10);
|
||||
if (*p) {
|
||||
log_fatal("option", "tried to convert {} to integer ({})", this->value, this->definition.title);
|
||||
log_fatal("option", "failed to convert {} to unsigned integer (option: {})", this->value, this->definition.title);
|
||||
return 0;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t Option::value_hex64() const {
|
||||
if (this->definition.type != OptionType::Hex) {
|
||||
log_fatal("option", "invalid call: value_hex() called on {}/{}", this->definition.title, this->definition.type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t affinity = 0;
|
||||
try {
|
||||
affinity = std::stoull(this->value.c_str(), nullptr, 16);
|
||||
} catch (const std::exception &ex) {
|
||||
log_fatal("option", "failed to parse {} as hexadecimal (option: {})", this->value, this->definition.title);
|
||||
}
|
||||
return affinity;
|
||||
}
|
||||
|
||||
+3
-1
@@ -9,6 +9,7 @@ enum class OptionType {
|
||||
Text,
|
||||
Integer,
|
||||
Enum,
|
||||
Hex,
|
||||
};
|
||||
|
||||
struct OptionDefinition {
|
||||
@@ -54,5 +55,6 @@ public:
|
||||
const std::string &value_text() const;
|
||||
std::vector<std::string> values() const;
|
||||
std::vector<std::string> values_text() const;
|
||||
int value_int() const;
|
||||
uint32_t value_uint32() const;
|
||||
uint64_t value_hex64() const;
|
||||
};
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
#define IDR_LICENSES 131
|
||||
#define IDR_PATCHES 132
|
||||
#define IDR_README 133
|
||||
#define IDR_DSEGFONT 134
|
||||
|
||||
+167
-76
@@ -1,11 +1,12 @@
|
||||
#include "screen_resize.h"
|
||||
|
||||
#include "external/rapidjson/document.h"
|
||||
#include "external/rapidjson/writer.h"
|
||||
#include "external/rapidjson/pointer.h"
|
||||
#include "external/rapidjson/prettywriter.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "util/utils.h"
|
||||
#include "util/fileutils.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
#include "hooks/graphics/graphics.h"
|
||||
|
||||
namespace cfg {
|
||||
|
||||
@@ -26,90 +27,180 @@ namespace cfg {
|
||||
log_info("ScreenResize", "loading config");
|
||||
|
||||
std::string config = fileutils::text_read(this->config_path);
|
||||
if (!config.empty()) {
|
||||
if (config.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// parse document
|
||||
Document doc;
|
||||
doc.Parse(config.c_str());
|
||||
// parse document
|
||||
rapidjson::Document doc;
|
||||
doc.Parse(config.c_str());
|
||||
|
||||
// check parse error
|
||||
auto error = doc.GetParseError();
|
||||
if (error) {
|
||||
log_warning("ScreenResize", "config parse error: {}", error);
|
||||
}
|
||||
// check parse error
|
||||
auto error = doc.GetParseError();
|
||||
if (error) {
|
||||
log_warning("ScreenResize", "config parse error: {}", error);
|
||||
return;
|
||||
}
|
||||
|
||||
// verify root is a dict
|
||||
if (doc.IsObject()) {
|
||||
bool valid = true;
|
||||
auto offset_x = doc.FindMember("offset_x");
|
||||
if (offset_x == doc.MemberEnd() || !offset_x->value.IsInt()) {
|
||||
log_warning("ScreenResize", "offset_x not found");
|
||||
valid = false;
|
||||
}
|
||||
auto offset_y = doc.FindMember("offset_y");
|
||||
if (offset_y == doc.MemberEnd() || !offset_y->value.IsInt()) {
|
||||
log_warning("ScreenResize", "offset_y not found");
|
||||
valid = false;
|
||||
}
|
||||
auto scale_x = doc.FindMember("scale_x");
|
||||
if (scale_x == doc.MemberEnd() || !scale_x->value.IsDouble()) {
|
||||
log_warning("ScreenResize", "scale_x not found");
|
||||
valid = false;
|
||||
}
|
||||
auto scale_y = doc.FindMember("scale_y");
|
||||
if (scale_y == doc.MemberEnd() || !scale_y->value.IsDouble()) {
|
||||
log_warning("ScreenResize", "scale_y not found");
|
||||
valid = false;
|
||||
}
|
||||
auto enable_screen_resize = doc.FindMember("enable_screen_resize");
|
||||
if (enable_screen_resize == doc.MemberEnd() || !enable_screen_resize->value.IsBool()) {
|
||||
log_warning("ScreenResize", "enable_screen_resize not found");
|
||||
valid = false;
|
||||
}
|
||||
auto enable_linear_filter = doc.FindMember("enable_linear_filter");
|
||||
if (enable_linear_filter == doc.MemberEnd() || !enable_linear_filter->value.IsBool()) {
|
||||
log_warning("ScreenResize", "enable_linear_filter not found");
|
||||
valid = false;
|
||||
}
|
||||
auto keep_aspect_ratio = doc.FindMember("keep_aspect_ratio");
|
||||
if (keep_aspect_ratio == doc.MemberEnd() || !keep_aspect_ratio->value.IsBool()) {
|
||||
log_warning("ScreenResize", "keep_aspect_ratio not found");
|
||||
valid = false;
|
||||
}
|
||||
if (valid) {
|
||||
this->offset_x = offset_x->value.GetInt();
|
||||
this->offset_y = offset_y->value.GetInt();
|
||||
this->scale_x = (float)scale_x->value.GetDouble();
|
||||
this->scale_y = (float)scale_y->value.GetDouble();
|
||||
this->enable_screen_resize = enable_screen_resize->value.GetBool();
|
||||
this->enable_linear_filter = enable_linear_filter->value.GetBool();
|
||||
this->keep_aspect_ratio = keep_aspect_ratio->value.GetBool();
|
||||
}
|
||||
} else {
|
||||
log_warning("ScreenResize", "config not found");
|
||||
// verify root is a dict
|
||||
if (!doc.IsObject()) {
|
||||
log_warning("ScreenResize", "config not found");
|
||||
return;
|
||||
}
|
||||
|
||||
bool use_game_setting = false;
|
||||
|
||||
std::string root("/");
|
||||
// try to find game-specific setting, if one exists
|
||||
{
|
||||
const auto game = rapidjson::Pointer("/sp2x_games/" + eamuse_get_game()).Get(doc);
|
||||
if (game && game->IsObject()) {
|
||||
use_game_setting = true;
|
||||
root = "/sp2x_games/" + eamuse_get_game() + "/";
|
||||
}
|
||||
}
|
||||
|
||||
log_misc(
|
||||
"ScreenResize",
|
||||
"Loading fullscreen image settings. Game = {}, is_global = {}, JSON path: {}",
|
||||
eamuse_get_game(),
|
||||
use_game_setting,
|
||||
root);
|
||||
load_int_value(doc, root + "offset_x", this->offset_x);
|
||||
load_int_value(doc, root + "offset_y", this->offset_y);
|
||||
load_float_value(doc, root + "scale_x", this->scale_x);
|
||||
load_float_value(doc, root + "scale_y", this->scale_y);
|
||||
load_bool_value(doc, root + "enable_screen_resize", this->enable_screen_resize);
|
||||
load_bool_value(doc, root + "enable_linear_filter", this->enable_linear_filter);
|
||||
load_bool_value(doc, root + "keep_aspect_ratio", this->keep_aspect_ratio);
|
||||
load_bool_value(doc, root + "centered", this->centered);
|
||||
|
||||
// windowed settings are always under game settings
|
||||
root = "/sp2x_games/" + eamuse_get_game() + "/";
|
||||
log_misc(
|
||||
"ScreenResize",
|
||||
"Loading window settings. Game = {}, JSON path: {}",
|
||||
eamuse_get_game(),
|
||||
root);
|
||||
load_bool_value(doc, root + "w_always_on_top", this->window_always_on_top);
|
||||
load_bool_value(doc, root + "w_enable_resize", this->enable_window_resize);
|
||||
load_bool_value(doc, root + "w_keep_aspect_ratio", this->client_keep_aspect_ratio);
|
||||
load_int_value(doc, root + "w_border_type", this->window_decoration);
|
||||
load_uint32_value(doc, root + "w_width", this->client_width);
|
||||
load_uint32_value(doc, root + "w_height", this->client_height);
|
||||
load_int_value(doc, root + "w_offset_x", this->window_offset_x);
|
||||
load_int_value(doc, root + "w_offset_y", this->window_offset_y);
|
||||
}
|
||||
|
||||
bool ScreenResize::load_bool_value(rapidjson::Document& doc, std::string path, bool& value) {
|
||||
const auto v = rapidjson::Pointer(path).Get(doc);
|
||||
if (!v) {
|
||||
log_warning("ScreenResize", "{} not found", path);
|
||||
return false;
|
||||
}
|
||||
if (!v->IsBool()) {
|
||||
log_warning("ScreenResize", "{} is invalid type", path);
|
||||
return false;
|
||||
}
|
||||
value = v->GetBool();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScreenResize::load_int_value(rapidjson::Document& doc, std::string path, int& value) {
|
||||
const auto v = rapidjson::Pointer(path).Get(doc);
|
||||
if (!v) {
|
||||
log_warning("ScreenResize", "{} not found", path);
|
||||
return false;
|
||||
}
|
||||
if (!v->IsInt()) {
|
||||
log_warning("ScreenResize", "{} is invalid type", path);
|
||||
return false;
|
||||
}
|
||||
value = v->GetInt();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScreenResize::load_uint32_value(rapidjson::Document& doc, std::string path, uint32_t& value) {
|
||||
const auto v = rapidjson::Pointer(path).Get(doc);
|
||||
if (!v) {
|
||||
log_warning("ScreenResize", "{} not found", path);
|
||||
return false;
|
||||
}
|
||||
if (!v->IsUint()) {
|
||||
log_warning("ScreenResize", "{} is invalid type", path);
|
||||
return false;
|
||||
}
|
||||
value = v->GetUint();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScreenResize::load_float_value(rapidjson::Document& doc, std::string path, float& value) {
|
||||
const auto v = rapidjson::Pointer(path).Get(doc);
|
||||
if (!v) {
|
||||
log_warning("ScreenResize", "{} not found", path);
|
||||
return false;
|
||||
}
|
||||
if (v->IsInt()) {
|
||||
value = v->GetInt();
|
||||
return true;
|
||||
}
|
||||
if (v->IsDouble()) {
|
||||
value = v->GetDouble();
|
||||
return true;
|
||||
}
|
||||
if (v->IsFloat()) {
|
||||
value = v->GetFloat();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScreenResize::config_save() {
|
||||
log_info("ScreenResize", "saving config");
|
||||
|
||||
// create document
|
||||
Document doc;
|
||||
doc.SetObject();
|
||||
auto &alloc = doc.GetAllocator();
|
||||
|
||||
doc.AddMember("offset_x", this->offset_x, alloc);
|
||||
doc.AddMember("offset_y", this->offset_y, alloc);
|
||||
doc.AddMember("scale_x", this->scale_x, alloc);
|
||||
doc.AddMember("scale_y", this->scale_y, alloc);
|
||||
doc.AddMember("enable_screen_resize", this->enable_screen_resize, alloc);
|
||||
doc.AddMember("enable_linear_filter", this->enable_linear_filter, alloc);
|
||||
doc.AddMember("keep_aspect_ratio", this->keep_aspect_ratio, alloc);
|
||||
|
||||
rapidjson::Document doc;
|
||||
std::string config = fileutils::text_read(this->config_path);
|
||||
if (!config.empty()) {
|
||||
doc.Parse(config.c_str());
|
||||
log_misc("ScreenResize", "existing config file found");
|
||||
}
|
||||
if (!doc.IsObject()) {
|
||||
log_misc("ScreenResize", "clearing out config file");
|
||||
doc.SetObject();
|
||||
}
|
||||
|
||||
// always save under per-game settings
|
||||
std::string root("/sp2x_games/" + eamuse_get_game() + "/");
|
||||
|
||||
log_misc(
|
||||
"ScreenResize",
|
||||
"Game = {}, JSON path = {}",
|
||||
eamuse_get_game(),
|
||||
root);
|
||||
|
||||
// full screen image settings
|
||||
rapidjson::Pointer(root + "offset_x").Set(doc, this->offset_x);
|
||||
rapidjson::Pointer(root + "offset_y").Set(doc, this->offset_y);
|
||||
rapidjson::Pointer(root + "scale_x").Set(doc, this->scale_x);
|
||||
rapidjson::Pointer(root + "scale_y").Set(doc, this->scale_y);
|
||||
rapidjson::Pointer(root + "enable_screen_resize").Set(doc, this->enable_screen_resize);
|
||||
rapidjson::Pointer(root + "enable_linear_filter").Set(doc, this->enable_linear_filter);
|
||||
rapidjson::Pointer(root + "keep_aspect_ratio").Set(doc, this->keep_aspect_ratio);
|
||||
rapidjson::Pointer(root + "centered").Set(doc, this->centered);
|
||||
|
||||
// windowed mode settings
|
||||
rapidjson::Pointer(root + "w_always_on_top").Set(doc, this->window_always_on_top);
|
||||
rapidjson::Pointer(root + "w_enable_resize").Set(doc, this->enable_window_resize);
|
||||
rapidjson::Pointer(root + "w_keep_aspect_ratio").Set(doc, this->client_keep_aspect_ratio);
|
||||
rapidjson::Pointer(root + "w_border_type").Set(doc, this->window_decoration);
|
||||
rapidjson::Pointer(root + "w_width").Set(doc, this->client_width);
|
||||
rapidjson::Pointer(root + "w_height").Set(doc, this->client_height);
|
||||
rapidjson::Pointer(root + "w_offset_x").Set(doc, this->window_offset_x);
|
||||
rapidjson::Pointer(root + "w_offset_y").Set(doc, this->window_offset_y);
|
||||
|
||||
// build JSON
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
doc.Accept(writer);
|
||||
|
||||
// save to file
|
||||
|
||||
+38
-3
@@ -2,26 +2,61 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "external/rapidjson/document.h"
|
||||
|
||||
namespace cfg {
|
||||
|
||||
enum WindowDecorationMode {
|
||||
Default = 0,
|
||||
Borderless = 1,
|
||||
ResizableFrame = 2
|
||||
};
|
||||
|
||||
class ScreenResize {
|
||||
private:
|
||||
std::string config_path;
|
||||
// bool config_dirty = false;
|
||||
|
||||
bool load_bool_value(rapidjson::Document& doc, std::string path, bool& value);
|
||||
bool load_int_value(rapidjson::Document& doc, std::string path, int& value);
|
||||
bool load_uint32_value(rapidjson::Document& doc, std::string path, uint32_t& value);
|
||||
bool load_float_value(rapidjson::Document& doc, std::string path, float& value);
|
||||
|
||||
public:
|
||||
ScreenResize();
|
||||
~ScreenResize();
|
||||
|
||||
// full screen (directx) image settings
|
||||
int offset_x = 0;
|
||||
int offset_y = 0;
|
||||
float scale_x = 1.0;
|
||||
float scale_y = 1.0;
|
||||
bool enable_screen_resize = false;
|
||||
bool enable_linear_filter = false;
|
||||
bool keep_aspect_ratio = false;
|
||||
|
||||
bool enable_linear_filter = true;
|
||||
bool keep_aspect_ratio = true;
|
||||
bool centered = true;
|
||||
|
||||
// windowed mode sizing
|
||||
// Windows terminology:
|
||||
// window = rectangle including the frame
|
||||
// client = just the content area without frames.
|
||||
bool window_always_on_top = false;
|
||||
bool client_keep_aspect_ratio = true;
|
||||
bool enable_window_resize = false;
|
||||
int window_decoration = 0; // enum type WindowDecorationMode
|
||||
uint32_t client_width = 0;
|
||||
uint32_t client_height = 0;
|
||||
int32_t window_offset_x = 0;
|
||||
int32_t window_offset_y = 0;
|
||||
|
||||
// these are not saved by config, but used by window management
|
||||
uint32_t init_client_width = 0;
|
||||
uint32_t init_client_height = 0;
|
||||
float init_client_aspect_ratio = 1.f;
|
||||
uint32_t init_window_style = 0;
|
||||
uint32_t window_deco_width = 0;
|
||||
uint32_t window_deco_height = 0;
|
||||
|
||||
void config_load();
|
||||
void config_save();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user