mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-01-11 18:41:14 +00:00
431 lines
14 KiB
C++
431 lines
14 KiB
C++
#include <app_settings.h>
|
|
#include <iniparser.h>
|
|
#include <paf.h>
|
|
#include <psp2/appmgr.h>
|
|
#include <psp2/io/fcntl.h>
|
|
#include <psp2/kernel/clib.h>
|
|
#include <psp2/kernel/modulemgr.h>
|
|
#include <psp2/sysmodule.h>
|
|
|
|
int sceLibcHeapSize = 10 * 1024 * 1024;
|
|
|
|
const char* g_iniPath = "ux0:data/isledecomp/isle/isle.ini";
|
|
|
|
paf::Framework* g_fw;
|
|
paf::Plugin* g_configPlugin;
|
|
sce::AppSettings* g_appSettings;
|
|
sce::AppSettings::Interface* g_appSetIf;
|
|
|
|
void merge_dicts(dictionary* dst, dictionary* src)
|
|
{
|
|
for (int i = 0; i < src->n; i++) {
|
|
dictionary_set(dst, src->key[i], src->val[i]);
|
|
}
|
|
}
|
|
|
|
struct setting_map {
|
|
const char* key_ini;
|
|
const char* key_app;
|
|
const char type;
|
|
};
|
|
|
|
// mapping from ini key to settings.xml key
|
|
const setting_map key_map[] = {
|
|
// Game
|
|
{"isle:diskpath", "disk_path", 's'},
|
|
{"isle:cdpath", "cd_path", 's'},
|
|
{"isle:savepath", "save_path", 's'},
|
|
{"isle:Transition Type", "transition_type", 'i'},
|
|
{"isle:Music", "music", 'b'},
|
|
{"isle:3DSound", "3d_sound", 'b'},
|
|
|
|
// Graphics
|
|
{"isle:Island Texture", "island_texture_quality", 'i'},
|
|
{"isle:Island Quality", "island_model_quality", 'i'},
|
|
//{"isle:Max LOD", "max_lod", 'f'},
|
|
//{"isle:Max Allowed Extras", "max_extras", 'i' },
|
|
{"isle:MSAA", "msaa", 'i'},
|
|
|
|
// Controls
|
|
{"isle:Touch Scheme", "touch_control_scheme", 'i'},
|
|
{"isle:Haptic", "rumble", 'b'},
|
|
|
|
// Extensions
|
|
{"extensions:texture loader", "texture_loader_extension", 'b'},
|
|
{"texture loader:texture path", "texture_loader_path", 's'}
|
|
};
|
|
|
|
struct Config {
|
|
sce::AppSettings* settings;
|
|
dictionary* dict;
|
|
char buffer[128];
|
|
|
|
#define GetDictInt(x, name) x = iniparser_getint(this->dict, name, x)
|
|
#define GetDictFloat(x, name) x = iniparser_getdouble(this->dict, name, x)
|
|
#define GetDictString(x, name) \
|
|
{ \
|
|
const char* val = iniparser_getstring(this->dict, name, nullptr); \
|
|
if (val != nullptr) { \
|
|
x = val; \
|
|
} \
|
|
}
|
|
#define GetDictBool(x, name) x = iniparser_getboolean(this->dict, name, x)
|
|
|
|
#define SetDictBool(NAME, VALUE) \
|
|
{ \
|
|
const char* v = VALUE ? "true" : "false"; \
|
|
sceClibPrintf("SetIniBool(%s, %s)\n", NAME, v); \
|
|
iniparser_set(this->dict, NAME, v); \
|
|
}
|
|
#define SetDictInt(NAME, VALUE) \
|
|
{ \
|
|
sceClibSnprintf(buffer, sizeof(buffer), "%d", VALUE); \
|
|
sceClibPrintf("SetIniInt(%s, %d)\n", NAME, VALUE); \
|
|
iniparser_set(this->dict, NAME, buffer); \
|
|
}
|
|
#define SetDictFloat(NAME, VALUE) \
|
|
{ \
|
|
sceClibSnprintf(buffer, sizeof(buffer), "%f", VALUE); \
|
|
sceClibPrintf("SetIniFloat(%s, %f)\n", NAME, VALUE); \
|
|
iniparser_set(this->dict, NAME, buffer); \
|
|
}
|
|
#define SetDictString(NAME, VALUE) \
|
|
{ \
|
|
sceClibPrintf("SetString(%s, %s)\n", NAME, VALUE); \
|
|
iniparser_set(this->dict, NAME, VALUE); \
|
|
}
|
|
|
|
void Init(sce::AppSettings* settings)
|
|
{
|
|
this->settings = settings;
|
|
dict = dictionary_new(0);
|
|
|
|
// set defaults
|
|
iniparser_set(this->dict, "isle", nullptr);
|
|
iniparser_set(dict, "extensions", NULL);
|
|
iniparser_set(this->dict, "texture loader", nullptr);
|
|
|
|
SetDictString("isle:diskpath", "ux0:data/isledecomp/isle/disk");
|
|
SetDictString("isle:cdpath", "ux0:data/isledecomp/isle/cd");
|
|
SetDictString("isle:savepath", "ux0:data/isledecomp/isle");
|
|
SetDictInt("isle:MSAA", 4);
|
|
|
|
SetDictInt("isle:Display Bit Depth", 32);
|
|
SetDictBool("isle:Flip Surfaces", false);
|
|
SetDictBool("isle:Full Screen", true);
|
|
SetDictBool("isle:Exclusive Full Screen", true);
|
|
SetDictBool("isle:Wide View Angle", true);
|
|
|
|
SetDictInt("isle:Transition Type", 3); // 3: Mosaic
|
|
SetDictInt("isle:Touch Scheme", 2);
|
|
|
|
SetDictBool("isle:3DSound", true);
|
|
SetDictBool("isle:Music", true);
|
|
SetDictBool("isle:Haptic", true);
|
|
|
|
SetDictBool("isle:UseJoystick", true);
|
|
SetDictInt("isle:JoystickIndex", 0);
|
|
SetDictBool("isle:Draw Cursor", true);
|
|
|
|
SetDictBool("extensions:texture loader", false);
|
|
SetDictString("texture loader:texture path", "textures/");
|
|
|
|
SetDictBool("isle:Back Buffers in Video RAM", true);
|
|
|
|
SetDictInt("isle:Island Quality", 2);
|
|
SetDictInt("isle:Island Texture", 1);
|
|
SetDictInt("isle:MSAA", 4);
|
|
|
|
SetDictFloat("isle:Max LOD", 3.5);
|
|
SetDictInt("isle:Max Allowed Extras", 20);
|
|
|
|
SetDictInt("isle:Aspect Ratio", 0);
|
|
SetDictInt("isle:Horizontal Resolution", 640);
|
|
SetDictInt("isle:Vertical Resolution", 480);
|
|
SetDictFloat("isle:Frame Delta", 10.0f);
|
|
}
|
|
|
|
void LoadIni()
|
|
{
|
|
dictionary* ini = iniparser_load(g_iniPath);
|
|
if (ini) {
|
|
merge_dicts(this->dict, ini);
|
|
iniparser_freedict(ini);
|
|
}
|
|
}
|
|
|
|
bool SaveIni()
|
|
{
|
|
FILE* fd = fopen(g_iniPath, "w");
|
|
if (fd) {
|
|
iniparser_dump_ini(this->dict, fd);
|
|
}
|
|
else {
|
|
sceClibPrintf("failed to write isle.ini\n");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ToSettings()
|
|
{
|
|
const int len = sizeof(key_map) / sizeof(key_map[0]);
|
|
for (int i = 0; i < len; i++) {
|
|
const setting_map m = key_map[i];
|
|
switch (m.type) {
|
|
case 'f': // float, AppSettings doesnt have float so just use string
|
|
case 's': {
|
|
const char* value = iniparser_getstring(this->dict, m.key_ini, "");
|
|
this->settings->SetString(m.key_app, value);
|
|
sceClibPrintf("ini->settings %s = %s\n", m.key_app, value);
|
|
break;
|
|
}
|
|
case 'i': {
|
|
int32_t value = iniparser_getint(this->dict, m.key_ini, 0);
|
|
this->settings->SetInt(m.key_app, value);
|
|
sceClibPrintf("ini->settings %s = %d\n", m.key_app, value);
|
|
break;
|
|
}
|
|
case 'b': {
|
|
bool value = iniparser_getboolean(this->dict, m.key_ini, 0) == 1;
|
|
this->settings->SetBool(m.key_app, value);
|
|
sceClibPrintf("ini->settings %s = %s\n", m.key_app, value ? "true" : "false");
|
|
break;
|
|
}
|
|
default: {
|
|
sceClibPrintf("invalid setting map entry %s %s %c\n", m.key_app, m.key_ini, m.type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FromSettings()
|
|
{
|
|
const int len = sizeof(key_map) / sizeof(key_map[0]);
|
|
for (int i = 0; i < len; i++) {
|
|
const setting_map m = key_map[i];
|
|
switch (m.type) {
|
|
case 'f': // float, AppSettings doesnt have float so just use string
|
|
case 's': {
|
|
const char* def = iniparser_getstring(this->dict, m.key_ini, "");
|
|
this->settings->GetString(m.key_app, this->buffer, sizeof(this->buffer), def);
|
|
iniparser_set(this->dict, m.key_ini, buffer);
|
|
sceClibPrintf("settings->ini %s = %s\n", m.key_ini, buffer);
|
|
break;
|
|
}
|
|
case 'i': {
|
|
int32_t value = iniparser_getint(this->dict, m.key_ini, 0);
|
|
this->settings->GetInt(m.key_app, &value, value);
|
|
SetDictInt(m.key_ini, value);
|
|
sceClibPrintf("settings->ini %s = %d\n", m.key_ini, value);
|
|
break;
|
|
}
|
|
case 'b': {
|
|
bool value = iniparser_getboolean(this->dict, m.key_ini, 0) == 1;
|
|
this->settings->GetBool(m.key_app, &value, value);
|
|
SetDictBool(m.key_ini, value);
|
|
sceClibPrintf("settings->ini %s = %s\n", m.key_ini, value ? "true" : "false");
|
|
break;
|
|
}
|
|
default: {
|
|
sceClibPrintf("invalid setting map entry %s %s %c\n", m.key_app, m.key_ini, m.type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Config g_config;
|
|
|
|
paf::Plugin* load_config_plugin(paf::Framework* paf_fw)
|
|
{
|
|
paf::Plugin::InitParam pluginParam;
|
|
pluginParam.name = "config_plugin";
|
|
pluginParam.caller_name = "__main__";
|
|
pluginParam.resource_file = "app0:/config_plugin.rco";
|
|
pluginParam.init_func = NULL;
|
|
pluginParam.start_func = NULL;
|
|
pluginParam.stop_func = NULL;
|
|
pluginParam.exit_func = NULL;
|
|
paf::Plugin::LoadSync(pluginParam);
|
|
return paf_fw->FindPlugin("config_plugin");
|
|
}
|
|
|
|
int load_app_settings_plugin()
|
|
{
|
|
paf::Plugin::InitParam pluginParam;
|
|
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_BXCE);
|
|
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_INI_FILE_PROCESSOR);
|
|
sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_COMMON_GUI_DIALOG);
|
|
|
|
pluginParam.name = "app_settings_plugin";
|
|
pluginParam.resource_file = "vs0:vsh/common/app_settings_plugin.rco";
|
|
pluginParam.caller_name = "__main__";
|
|
pluginParam.set_param_func = sce::AppSettings::PluginSetParamCB;
|
|
pluginParam.init_func = sce::AppSettings::PluginInitCB;
|
|
pluginParam.start_func = sce::AppSettings::PluginStartCB;
|
|
pluginParam.stop_func = sce::AppSettings::PluginStopCB;
|
|
pluginParam.exit_func = sce::AppSettings::PluginExitCB;
|
|
pluginParam.module_file = "vs0:vsh/common/app_settings.suprx";
|
|
pluginParam.draw_priority = 0x96;
|
|
paf::Plugin::LoadSync(pluginParam);
|
|
return 0;
|
|
}
|
|
|
|
int exit_type = 0;
|
|
|
|
void save_and_exit()
|
|
{
|
|
g_config.FromSettings();
|
|
g_config.SaveIni();
|
|
g_fw->RequestShutdown();
|
|
exit_type = 1;
|
|
}
|
|
|
|
void save_and_launch()
|
|
{
|
|
g_config.FromSettings();
|
|
g_config.SaveIni();
|
|
g_fw->RequestShutdown();
|
|
exit_type = 2;
|
|
}
|
|
|
|
void CBOnStartPageTransition(const char* elementId, int32_t type)
|
|
{
|
|
}
|
|
|
|
void CBOnPageActivate(const char* elementId, int32_t type)
|
|
{
|
|
}
|
|
|
|
void CBOnPageDeactivate(const char* elementId, int32_t type)
|
|
{
|
|
}
|
|
|
|
int32_t CBOnCheckVisible(const char* elementId, bool* pIsVisible)
|
|
{
|
|
*pIsVisible = true;
|
|
return SCE_OK;
|
|
}
|
|
|
|
int32_t CBOnPreCreate(const char* elementId, sce::AppSettings::Element* element)
|
|
{
|
|
return SCE_OK;
|
|
}
|
|
|
|
int32_t CBOnPostCreate(const char* elementId, paf::ui::Widget* widget)
|
|
{
|
|
return SCE_OK;
|
|
}
|
|
|
|
int32_t CBOnPress(const char* elementId, const char* newValue)
|
|
{
|
|
if (sce_paf_strcmp(elementId, "save_exit_button") == 0) {
|
|
save_and_exit();
|
|
return SCE_OK;
|
|
}
|
|
|
|
if (sce_paf_strcmp(elementId, "save_launch_button") == 0) {
|
|
save_and_launch();
|
|
return SCE_OK;
|
|
}
|
|
|
|
sceClibPrintf("OnPress %s %s\n", elementId, newValue);
|
|
return SCE_OK;
|
|
}
|
|
|
|
int32_t CBOnPress2(const char* elementId, const char* newValue)
|
|
{
|
|
return SCE_OK;
|
|
}
|
|
|
|
void CBOnTerm(int32_t result)
|
|
{
|
|
if (exit_type == 0) {
|
|
sceKernelExitProcess(0);
|
|
}
|
|
}
|
|
|
|
const wchar_t* CBOnGetString(const char* elementId)
|
|
{
|
|
wchar_t* res = g_configPlugin->GetString(elementId);
|
|
if (res[0] != 0) {
|
|
return res;
|
|
}
|
|
return L"unknown string";
|
|
}
|
|
|
|
int32_t CBOnGetSurface(paf::graph::Surface** surf, const char* elementId)
|
|
{
|
|
return SCE_OK;
|
|
}
|
|
|
|
void open_settings()
|
|
{
|
|
g_config.Init(g_appSettings);
|
|
g_config.LoadIni();
|
|
g_config.ToSettings();
|
|
|
|
sce::AppSettings::InterfaceCallbacks ifCb;
|
|
ifCb.onStartPageTransitionCb = CBOnStartPageTransition;
|
|
ifCb.onPageActivateCb = CBOnPageActivate;
|
|
ifCb.onPageDeactivateCb = CBOnPageDeactivate;
|
|
ifCb.onCheckVisible = CBOnCheckVisible;
|
|
ifCb.onPreCreateCb = CBOnPreCreate;
|
|
ifCb.onPostCreateCb = CBOnPostCreate;
|
|
ifCb.onPressCb = CBOnPress;
|
|
ifCb.onPressCb2 = CBOnPress2;
|
|
ifCb.onTermCb = CBOnTerm;
|
|
ifCb.onGetStringCb = (sce::AppSettings::InterfaceCallbacks::GetStringCallback) CBOnGetString;
|
|
ifCb.onGetSurfaceCb = CBOnGetSurface;
|
|
|
|
paf::wstring msg_save_exit(g_configPlugin->GetString("msg_save_exit"));
|
|
paf::wstring msg_save_launch(g_configPlugin->GetString("msg_save_launch"));
|
|
paf::wstring msg_exit(g_configPlugin->GetString("msg_exit"));
|
|
|
|
paf::Plugin* appSetPlug = paf::Plugin::Find("app_settings_plugin");
|
|
g_appSetIf = (sce::AppSettings::Interface*) appSetPlug->GetInterface(1);
|
|
g_appSetIf->Show(&ifCb);
|
|
g_appSetIf->AddFooterButton("save_exit_button", &msg_save_exit, 1);
|
|
g_appSetIf->AddFooterButton("save_launch_button", &msg_save_launch, 2);
|
|
g_appSetIf->ShowFooter();
|
|
}
|
|
|
|
int main()
|
|
{
|
|
paf::Framework::InitParam fwParam;
|
|
fwParam.mode = paf::Framework::Mode_Normal;
|
|
|
|
paf::Framework* paf_fw = new paf::Framework(fwParam);
|
|
g_fw = paf_fw;
|
|
|
|
paf_fw->LoadCommonResourceSync();
|
|
load_app_settings_plugin();
|
|
paf::Plugin* configPlugin = load_config_plugin(paf_fw);
|
|
g_configPlugin = configPlugin;
|
|
configPlugin->SetLocale(Locale_EN);
|
|
|
|
size_t fileSize = 0;
|
|
const char* mimeType = nullptr;
|
|
auto settingsXmlFile = configPlugin->GetResource()->GetFile("settings.xml", &fileSize, &mimeType);
|
|
|
|
sce::AppSettings::InitParam settingsParam;
|
|
settingsParam.xml_file = settingsXmlFile;
|
|
settingsParam.alloc_cb = sce_paf_malloc;
|
|
settingsParam.free_cb = sce_paf_free;
|
|
settingsParam.realloc_cb = sce_paf_realloc;
|
|
settingsParam.safemem_offset = 0;
|
|
settingsParam.safemem_size = 0x400;
|
|
|
|
sce::AppSettings::GetInstance(settingsParam, &g_appSettings);
|
|
g_appSettings->Initialize();
|
|
|
|
open_settings();
|
|
paf_fw->Run();
|
|
|
|
if (exit_type == 2) {
|
|
int ret = sceAppMgrLoadExec("app0:/eboot.bin", NULL, NULL);
|
|
printf("sceAppMgrLoadExec: %08x\n", ret);
|
|
}
|
|
return 0;
|
|
}
|