2011-07-03 16:09:28 +02:00
|
|
|
/*
|
2019-08-03 19:43:48 +02:00
|
|
|
* This software is licensed under the terms of the MIT License.
|
2017-02-11 02:24:47 +01:00
|
|
|
* See COPYING for further information.
|
2011-07-03 16:09:28 +02:00
|
|
|
* ---
|
2024-05-16 23:30:41 +02:00
|
|
|
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
|
|
|
|
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
|
2011-07-03 16:09:28 +02:00
|
|
|
*/
|
2011-07-03 15:11:18 +02:00
|
|
|
|
2024-05-17 04:41:28 +02:00
|
|
|
#include "options.h"
|
2019-11-22 04:37:11 +01:00
|
|
|
|
2017-02-12 04:43:52 +01:00
|
|
|
#include "common.h"
|
2024-05-27 19:12:28 +02:00
|
|
|
#include "config.h"
|
|
|
|
#include "events.h"
|
2019-04-20 18:06:27 +02:00
|
|
|
#include "mainmenu.h"
|
2024-05-17 04:41:28 +02:00
|
|
|
#include "menu.h"
|
|
|
|
|
|
|
|
#include "audio/audio.h"
|
|
|
|
#include "gamepad.h"
|
2024-05-27 19:12:28 +02:00
|
|
|
#include "renderer/api.h"
|
|
|
|
#include "resource/font.h"
|
2023-07-30 06:13:09 +02:00
|
|
|
#include "util/graphics.h"
|
2024-05-17 04:41:28 +02:00
|
|
|
#include "video.h"
|
|
|
|
|
2024-05-27 19:12:28 +02:00
|
|
|
#define OPTIONS_ACTIVE_X_OFFSET 20 /* FIXME hardcoded in draw_menu_list */
|
|
|
|
#define OPTIONS_ITEM_HEIGHT 20 /* FIXME hardcoded in draw_menu_list */
|
|
|
|
#define OPTIONS_X_MARGIN 100
|
|
|
|
#define OPTIONS_Y_MARGIN 100
|
2011-07-03 15:11:18 +02:00
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
typedef struct OptionBinding OptionBinding;
|
|
|
|
|
|
|
|
typedef int (*BindingGetter)(OptionBinding*);
|
|
|
|
typedef int (*BindingSetter)(OptionBinding*, int);
|
|
|
|
typedef bool (*BindingDependence)(void);
|
|
|
|
|
|
|
|
typedef enum BindingType {
|
|
|
|
BT_IntValue,
|
|
|
|
BT_KeyBinding,
|
|
|
|
BT_StrValue,
|
|
|
|
BT_Resolution,
|
2020-04-16 18:25:54 +02:00
|
|
|
BT_FramebufferResolution,
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
BT_Scale,
|
|
|
|
BT_GamepadKeyBinding,
|
|
|
|
BT_GamepadAxisBinding,
|
|
|
|
BT_GamepadDevice,
|
2019-04-18 21:56:16 +02:00
|
|
|
BT_VideoDisplay,
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
} BindingType;
|
|
|
|
|
2024-05-03 03:12:07 +02:00
|
|
|
typedef enum OptionsMenuEntryArgType {
|
|
|
|
ARGTYPE_BIND = 0xafafaf00,
|
|
|
|
ARGTYPE_OTHER,
|
|
|
|
} OptionsMenuEntryArgType;
|
|
|
|
|
|
|
|
// Shared header for all structs used as args in menu entries,
|
|
|
|
// because past me had the brilliant idea of storing the bindings in there
|
|
|
|
// and now there is a need to tell them apart from other stuff.
|
|
|
|
// One of these days I'm gonna rewrite this whole file from scratch (copium)
|
|
|
|
// along with the entire menu system (mega copium), but that day is not today.
|
|
|
|
typedef struct OptionsMenuArgHeader {
|
|
|
|
OptionsMenuEntryArgType type;
|
|
|
|
} OptionsMenuArgHeader;
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
typedef struct OptionBinding {
|
2024-05-03 03:12:07 +02:00
|
|
|
OptionsMenuArgHeader header;
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
union {
|
|
|
|
char **values;
|
|
|
|
char *strvalue;
|
|
|
|
};
|
|
|
|
bool displaysingle;
|
|
|
|
int valrange_min;
|
|
|
|
int valrange_max;
|
|
|
|
float scale_min;
|
|
|
|
float scale_max;
|
|
|
|
float scale_step;
|
|
|
|
BindingGetter getter;
|
|
|
|
BindingSetter setter;
|
|
|
|
BindingDependence dependence;
|
|
|
|
int selected;
|
|
|
|
int configentry;
|
|
|
|
BindingType type;
|
|
|
|
bool blockinput;
|
|
|
|
int pad;
|
|
|
|
} OptionBinding;
|
|
|
|
|
2011-07-03 21:35:55 +02:00
|
|
|
// --- Menu entry <-> config option binding stuff --- //
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_new(void) {
|
2023-01-09 04:19:31 +01:00
|
|
|
return ALLOC(OptionBinding, {
|
2024-05-03 03:12:07 +02:00
|
|
|
.header.type = ARGTYPE_BIND,
|
2023-01-09 04:19:31 +01:00
|
|
|
.selected = -1,
|
|
|
|
.configentry = -1,
|
|
|
|
});
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static void bind_free(OptionBinding *bind) {
|
2012-08-16 18:15:46 +02:00
|
|
|
int i;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2019-04-19 13:28:32 +02:00
|
|
|
if(bind->type == BT_StrValue) {
|
2023-01-09 04:19:31 +01:00
|
|
|
mem_free(bind->strvalue);
|
2019-04-19 13:28:32 +02:00
|
|
|
} else if(bind->values) {
|
|
|
|
assert(bind->valrange_min == 0);
|
|
|
|
for(i = 0; i <= bind->valrange_max; ++i) {
|
2023-01-09 04:19:31 +01:00
|
|
|
mem_free(*(bind->values+i));
|
2019-04-19 13:28:32 +02:00
|
|
|
}
|
2023-01-09 04:19:31 +01:00
|
|
|
mem_free(bind->values);
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
2012-08-16 18:15:46 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_get(MenuData *m, int idx) {
|
2020-04-05 04:51:00 +02:00
|
|
|
MenuEntry *e = dynarray_get_ptr(&m->entries, idx);
|
2024-05-03 03:12:07 +02:00
|
|
|
OptionsMenuArgHeader *header = e->arg;
|
|
|
|
|
|
|
|
if(!header) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(header->type == ARGTYPE_BIND) {
|
|
|
|
return CASTPTR_ASSUME_ALIGNED(header, OptionBinding);
|
|
|
|
}
|
|
|
|
|
|
|
|
assume(header->type == ARGTYPE_OTHER);
|
|
|
|
return NULL;
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
// BT_IntValue: integer and boolean options
|
|
|
|
// Values are defined with bind_addvalue or bind_setrange
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_option(int cfgentry, BindingGetter getter, BindingSetter setter) {
|
2012-08-16 23:35:48 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
bind->type = BT_IntValue;
|
|
|
|
bind->configentry = cfgentry;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2011-07-03 15:11:18 +02:00
|
|
|
bind->getter = getter;
|
|
|
|
bind->setter = setter;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2011-07-03 17:37:18 +02:00
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
// BT_KeyBinding: keyboard action mapping options
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_keybinding(int cfgentry) {
|
2012-08-16 23:35:48 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2011-07-03 17:37:18 +02:00
|
|
|
bind->configentry = cfgentry;
|
|
|
|
bind->type = BT_KeyBinding;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2011-07-03 15:11:18 +02:00
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
// BT_GamepadKeyBinding: gamepad action mapping options
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_gpbinding(int cfgentry) {
|
2012-08-17 00:41:33 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
bind->configentry = cfgentry;
|
|
|
|
bind->type = BT_GamepadKeyBinding;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2017-02-27 23:58:47 +01:00
|
|
|
// BT_GamepadAxisBinding: gamepad axis mapping options
|
2023-07-11 23:51:44 +02:00
|
|
|
attr_unused
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_gpaxisbinding(int cfgentry) {
|
2017-02-27 23:58:47 +01:00
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
|
|
|
|
bind->configentry = cfgentry;
|
|
|
|
bind->type = BT_GamepadAxisBinding;
|
|
|
|
|
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2017-08-28 13:51:05 +02:00
|
|
|
static int bind_gpdev_get(OptionBinding *b) {
|
2019-04-19 13:28:32 +02:00
|
|
|
const char *guid = config_get_str(b->configentry);
|
|
|
|
int val = gamepad_device_num_from_guid(guid);
|
|
|
|
|
|
|
|
if(val == GAMEPAD_DEVNUM_ANY) {
|
|
|
|
val = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
2017-08-28 13:51:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bind_gpdev_set(OptionBinding *b, int v) {
|
|
|
|
char guid[33] = {0};
|
2019-04-19 13:28:32 +02:00
|
|
|
|
|
|
|
if(v == -1) {
|
|
|
|
v = GAMEPAD_DEVNUM_ANY;
|
|
|
|
}
|
|
|
|
|
2017-12-30 16:38:35 +01:00
|
|
|
gamepad_device_guid(v, guid, sizeof(guid));
|
2017-08-28 13:51:05 +02:00
|
|
|
|
|
|
|
if(*guid) {
|
|
|
|
config_set_str(b->configentry, guid);
|
2019-04-19 13:28:32 +02:00
|
|
|
|
|
|
|
if(v == GAMEPAD_DEVNUM_ANY) {
|
|
|
|
v = -1;
|
|
|
|
}
|
|
|
|
|
2017-08-28 13:51:05 +02:00
|
|
|
b->selected = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
return b->selected;
|
|
|
|
}
|
|
|
|
|
2019-08-02 20:38:33 +02:00
|
|
|
#ifndef __SWITCH__
|
2017-08-28 13:51:05 +02:00
|
|
|
// BT_GamepadDevice: dynamic device list
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_gpdevice(int cfgentry) {
|
2017-08-28 13:51:05 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
|
|
|
|
bind->configentry = cfgentry;
|
|
|
|
bind->type = BT_GamepadDevice;
|
|
|
|
|
|
|
|
bind->getter = bind_gpdev_get;
|
|
|
|
bind->setter = bind_gpdev_set;
|
|
|
|
|
2019-04-19 13:28:32 +02:00
|
|
|
bind->valrange_min = -1;
|
2017-08-28 13:51:05 +02:00
|
|
|
bind->valrange_max = 0; // updated later
|
|
|
|
|
2017-12-30 16:38:35 +01:00
|
|
|
bind->selected = gamepad_device_num_from_guid(config_get_str(bind->configentry));
|
2017-08-28 13:51:05 +02:00
|
|
|
|
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
// BT_StrValue: with a half-assed "textbox"
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_stroption(ConfigIndex cfgentry) {
|
2012-08-16 23:35:48 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
2012-07-29 22:39:52 +02:00
|
|
|
bind->type = BT_StrValue;
|
2012-08-16 23:35:48 +02:00
|
|
|
bind->configentry = cfgentry;
|
2017-09-30 04:38:16 +02:00
|
|
|
stralloc(&bind->strvalue, config_get_str(cfgentry));
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-07-29 22:39:52 +02:00
|
|
|
return bind;
|
|
|
|
}
|
2019-08-02 20:38:33 +02:00
|
|
|
#endif
|
2012-07-29 22:39:52 +02:00
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
// BT_Resolution: super-special binding type for the resolution setting
|
2019-01-24 21:21:08 +01:00
|
|
|
static void bind_resolution_update(OptionBinding *bind) {
|
2020-04-16 18:25:54 +02:00
|
|
|
// FIXME This is brittle. The least we could do is to explicitly store whether the currently selected value represents a fullscreen index or windowed.
|
|
|
|
|
|
|
|
bool fullscreen = video_is_fullscreen();
|
2020-03-29 23:03:38 +02:00
|
|
|
uint nmodes = video_get_num_modes(fullscreen);
|
2019-09-11 17:42:13 +02:00
|
|
|
VideoMode cur = video_get_current_mode();
|
|
|
|
|
2020-04-16 18:25:54 +02:00
|
|
|
log_debug("Fullscreen: %i", fullscreen);
|
|
|
|
log_debug("Prev selected: %i", bind->selected);
|
|
|
|
|
2019-04-19 13:28:32 +02:00
|
|
|
bind->valrange_min = 0;
|
2019-09-11 17:42:13 +02:00
|
|
|
bind->valrange_max = nmodes - 1;
|
2020-04-16 18:25:54 +02:00
|
|
|
bind->selected = -1;
|
|
|
|
|
|
|
|
log_debug("nmodes = %i", nmodes);
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2019-09-11 17:42:13 +02:00
|
|
|
for(int i = 0; i < nmodes; ++i) {
|
2023-06-20 00:33:01 +02:00
|
|
|
VideoMode m;
|
|
|
|
attr_unused bool ok = video_get_mode(i, fullscreen, &m);
|
|
|
|
assert(ok);
|
|
|
|
|
2020-04-16 18:25:54 +02:00
|
|
|
log_debug("#%i %ix%i", i, m.width, m.height);
|
2019-09-11 17:42:13 +02:00
|
|
|
if(m.width == cur.width && m.height == cur.height) {
|
2017-03-01 01:40:50 +01:00
|
|
|
bind->selected = i;
|
2020-04-16 18:25:54 +02:00
|
|
|
log_debug("selected #%i", bind->selected);
|
2017-03-01 01:40:50 +01:00
|
|
|
}
|
|
|
|
}
|
2017-09-18 13:19:50 +02:00
|
|
|
}
|
2017-03-01 01:40:50 +01:00
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_resolution(void) {
|
2017-09-18 13:19:50 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
bind->type = BT_Resolution;
|
|
|
|
bind->selected = -1;
|
|
|
|
bind_resolution_update(bind);
|
2012-07-28 22:53:53 +02:00
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2020-04-16 18:25:54 +02:00
|
|
|
// BT_FramebufferResolution: not an actual setting (yet); just display effective resolution in pixels
|
|
|
|
// This may be different from BT_Resolution in the high-DPI case
|
|
|
|
// (BT_Resolution is a misnomer; it represents the window size in screen-space units)
|
|
|
|
static OptionBinding* bind_fb_resolution(void) {
|
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
bind->type = BT_FramebufferResolution;
|
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2012-08-17 00:41:33 +02:00
|
|
|
// BT_Scale: float values clamped to a range
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_scale(int cfgentry, float smin, float smax, float step) {
|
2012-08-16 23:35:48 +02:00
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
bind->type = BT_Scale;
|
|
|
|
bind->configentry = cfgentry;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
bind->scale_min = smin;
|
|
|
|
bind->scale_max = smax;
|
|
|
|
bind->scale_step = step;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2011-07-03 21:52:33 +02:00
|
|
|
// Returns a pointer to the first found binding that blocks input. If none found, returns NULL.
|
2019-01-24 21:21:08 +01:00
|
|
|
static OptionBinding* bind_getinputblocking(MenuData *m) {
|
2020-04-05 04:51:00 +02:00
|
|
|
dynarray_foreach_idx(&m->entries, int i, {
|
2012-08-16 18:15:46 +02:00
|
|
|
OptionBinding *bind = bind_get(m, i);
|
2020-04-05 04:51:00 +02:00
|
|
|
if(bind && bind->blockinput) {
|
2012-08-16 18:15:46 +02:00
|
|
|
return bind;
|
2020-04-05 04:51:00 +02:00
|
|
|
}
|
|
|
|
});
|
2011-07-03 21:35:55 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-03 21:52:33 +02:00
|
|
|
// Adds a value to a BT_IntValue type binding
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_addvalue(OptionBinding *b, char *val) {
|
2019-04-19 13:28:32 +02:00
|
|
|
assert(b->valrange_min == 0);
|
|
|
|
|
|
|
|
if(b->values == NULL) {
|
2023-01-09 04:19:31 +01:00
|
|
|
b->values = mem_alloc(sizeof(char*));
|
2019-04-19 13:28:32 +02:00
|
|
|
b->valrange_min = 0;
|
|
|
|
b->valrange_max = 0;
|
|
|
|
} else {
|
|
|
|
assert(b->valrange_min == 0);
|
|
|
|
++b->valrange_max;
|
|
|
|
}
|
|
|
|
|
2023-01-09 04:19:31 +01:00
|
|
|
b->values = mem_realloc(b->values, (1 + b->valrange_max) * sizeof(char*));
|
2024-09-05 06:38:58 +02:00
|
|
|
b->values[b->valrange_max] = mem_strdup(val);
|
2019-04-19 13:28:32 +02:00
|
|
|
return b->valrange_max;
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
attr_unused
|
|
|
|
static void bind_setvaluerange(OptionBinding *b, int vmin, int vmax) {
|
2019-04-19 13:28:32 +02:00
|
|
|
assert(b->values == NULL);
|
2012-07-13 22:42:35 +02:00
|
|
|
b->valrange_min = vmin;
|
|
|
|
b->valrange_max = vmax;
|
|
|
|
}
|
|
|
|
|
2011-07-03 21:52:33 +02:00
|
|
|
// Called to select a value of a BT_IntValue type binding by index
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_setvalue(OptionBinding *b, int v) {
|
2012-07-28 22:53:53 +02:00
|
|
|
if(b->setter)
|
|
|
|
return b->selected = b->setter(b, v);
|
|
|
|
else
|
|
|
|
return b->selected = v;
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2011-07-03 21:52:33 +02:00
|
|
|
// Called to get the selected value of a BT_IntValue type binding by index
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_getvalue(OptionBinding *b) {
|
2012-08-16 23:35:48 +02:00
|
|
|
if(b->getter) {
|
2019-04-19 13:28:32 +02:00
|
|
|
b->selected = b->getter(b);
|
2012-08-16 23:35:48 +02:00
|
|
|
}
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-08-16 23:35:48 +02:00
|
|
|
return b->selected;
|
2011-07-03 18:46:40 +02:00
|
|
|
}
|
|
|
|
|
2011-07-03 21:52:33 +02:00
|
|
|
// Selects the next to current value of a BT_IntValue type binding
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_setnext(OptionBinding *b) {
|
2017-08-28 13:51:05 +02:00
|
|
|
int s = b->selected + 1;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2019-04-19 13:28:32 +02:00
|
|
|
if(s > b->valrange_max) {
|
|
|
|
s = b->valrange_min;
|
2017-08-28 13:51:05 +02:00
|
|
|
}
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-07-13 22:42:35 +02:00
|
|
|
return bind_setvalue(b, s);
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2011-07-03 21:52:33 +02:00
|
|
|
// Selects the previous to current value of a BT_IntValue type binding
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_setprev(OptionBinding *b) {
|
2011-07-03 15:11:18 +02:00
|
|
|
int s = b->selected - 1;
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2019-04-19 13:28:32 +02:00
|
|
|
if(s < b->valrange_min) {
|
|
|
|
s = b->valrange_max;
|
2017-08-28 13:51:05 +02:00
|
|
|
}
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-07-13 22:42:35 +02:00
|
|
|
return bind_setvalue(b, s);
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static bool bind_isactive(OptionBinding *b) {
|
2012-07-13 22:42:35 +02:00
|
|
|
if(!b->dependence)
|
2017-02-11 04:52:08 +01:00
|
|
|
return true;
|
2012-07-13 22:42:35 +02:00
|
|
|
return b->dependence();
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2011-07-03 21:35:55 +02:00
|
|
|
// --- Shared binding callbacks --- //
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_onoff_get(OptionBinding *b) {
|
2017-03-02 11:23:30 +01:00
|
|
|
return !config_get_int(b->configentry);
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_onoff_set(OptionBinding *b, int v) {
|
2017-03-02 11:23:30 +01:00
|
|
|
return !config_set_int(b->configentry, !v);
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_onoff_inverted_get(OptionBinding *b) {
|
2017-03-02 11:23:30 +01:00
|
|
|
return config_get_int(b->configentry);
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_onoff_inverted_set(OptionBinding *b, int v) {
|
2017-03-02 11:23:30 +01:00
|
|
|
return config_set_int(b->configentry, v);
|
2011-07-03 15:11:18 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_onoffplus_get(OptionBinding *b) {
|
2017-09-26 23:55:28 +02:00
|
|
|
int v = config_get_int(b->configentry);
|
|
|
|
|
|
|
|
if(v > 1)
|
|
|
|
return v;
|
|
|
|
return !v;
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_onoffplus_set(OptionBinding *b, int v) {
|
2017-09-26 23:55:28 +02:00
|
|
|
if(v > 1)
|
|
|
|
return config_set_int(b->configentry, v);
|
|
|
|
return !config_set_int(b->configentry, !v);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define bind_common_int_get bind_common_onoff_inverted_get
|
|
|
|
#define bind_common_int_set bind_common_onoff_inverted_set
|
2012-07-13 22:42:35 +02:00
|
|
|
|
2019-04-18 21:56:16 +02:00
|
|
|
// BT_VideoDisplay: fullscreen display number
|
|
|
|
static OptionBinding* bind_video_display(int cfgentry) {
|
|
|
|
OptionBinding *bind = bind_new();
|
|
|
|
|
|
|
|
bind->configentry = cfgentry;
|
|
|
|
bind->type = BT_VideoDisplay;
|
|
|
|
|
|
|
|
bind->getter = bind_common_int_get;
|
|
|
|
bind->setter = bind_common_int_set;
|
|
|
|
|
|
|
|
bind->valrange_min = 0;
|
|
|
|
bind->valrange_max = 0; // updated later
|
|
|
|
|
|
|
|
bind->selected = video_current_display();
|
|
|
|
|
|
|
|
return bind;
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_intplus1_get(OptionBinding *b) {
|
2017-12-26 12:07:40 +01:00
|
|
|
return config_get_int(b->configentry) - 1;
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_common_intplus1_set(OptionBinding *b, int v) {
|
2017-12-26 12:07:40 +01:00
|
|
|
return config_set_int(b->configentry, v + 1) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-03 21:35:55 +02:00
|
|
|
// --- Binding callbacks for individual options --- //
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static bool bind_resizable_dependence(void) {
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
return video_query_capability(VIDEO_CAP_EXTERNAL_RESIZE) == VIDEO_AVAILABLE;
|
2017-03-01 01:25:52 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static bool bind_bgquality_dependence(void) {
|
2017-04-07 01:54:59 +02:00
|
|
|
return !config_get_int(CONFIG_NO_STAGEBG);
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static bool bind_resolution_dependence(void) {
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
return video_query_capability(VIDEO_CAP_CHANGE_RESOLUTION) == VIDEO_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2020-04-16 18:25:54 +02:00
|
|
|
static bool bind_fb_resolution_dependence(void) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
static bool bind_fullscreen_dependence(void) {
|
|
|
|
return video_query_capability(VIDEO_CAP_FULLSCREEN) == VIDEO_AVAILABLE;
|
2017-09-18 13:19:50 +02:00
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_resolution_set(OptionBinding *b, int v) {
|
2023-06-20 00:33:01 +02:00
|
|
|
VideoMode m;
|
|
|
|
|
|
|
|
if(video_get_mode(v, video_is_fullscreen(), &m)) {
|
2019-09-11 17:42:13 +02:00
|
|
|
config_set_int(CONFIG_VID_WIDTH, m.width);
|
|
|
|
config_set_int(CONFIG_VID_HEIGHT, m.height);
|
2017-03-01 01:40:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_power_set(OptionBinding *b, int v) {
|
2018-01-20 16:54:45 +01:00
|
|
|
return config_set_int(b->configentry, v * 100) / 100;
|
|
|
|
}
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static int bind_power_get(OptionBinding *b) {
|
2018-01-20 16:54:45 +01:00
|
|
|
return config_get_int(b->configentry) / 100;
|
|
|
|
}
|
|
|
|
|
2023-06-20 01:12:47 +02:00
|
|
|
static int bind_gamepad_set(OptionBinding *b, int v) {
|
|
|
|
v = bind_common_onoff_set(b, v);
|
|
|
|
if(v == 0) {
|
|
|
|
gamepad_init();
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2011-07-03 21:35:55 +02:00
|
|
|
// --- Creating, destroying, filling the menu --- //
|
|
|
|
|
2024-05-03 03:12:07 +02:00
|
|
|
typedef struct ConfirmDialog {
|
|
|
|
OptionsMenuArgHeader header;
|
|
|
|
const char *const text;
|
|
|
|
void (*const action)(void);
|
|
|
|
} ConfirmDialog;
|
|
|
|
|
|
|
|
static const ConfirmDialog dialog_reset_default = {
|
|
|
|
.header.type = ARGTYPE_OTHER,
|
|
|
|
.text = "Reset all settings to defaults?",
|
|
|
|
.action = config_reset,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const ConfirmDialog dialog_reset_saved = {
|
|
|
|
.header.type = ARGTYPE_OTHER,
|
|
|
|
.text = "Reset all settings to the last saved values?",
|
|
|
|
.action = config_load,
|
|
|
|
};
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
typedef struct OptionsMenuContext {
|
|
|
|
const char *title;
|
|
|
|
void *data;
|
2023-06-23 09:32:33 +02:00
|
|
|
MenuData *submenu;
|
|
|
|
MenuData *submenu_fading;
|
2024-05-03 03:12:07 +02:00
|
|
|
ConfirmDialog *confirm_dialog;
|
2023-06-23 09:32:33 +02:00
|
|
|
float submenu_alpha;
|
2024-05-27 19:12:28 +02:00
|
|
|
void (*draw_overlay)(MenuData *m, struct OptionsMenuContext *ctx);
|
|
|
|
struct {
|
|
|
|
bool allowed;
|
|
|
|
bool active;
|
|
|
|
} gamepad_testmode;
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
} OptionsMenuContext;
|
|
|
|
|
2019-01-24 21:21:08 +01:00
|
|
|
static void destroy_options_menu(MenuData *m) {
|
2019-04-18 21:56:16 +02:00
|
|
|
bool change_vidmode = false;
|
|
|
|
|
2020-04-05 04:51:00 +02:00
|
|
|
dynarray_foreach_idx(&m->entries, int i, {
|
2012-08-16 18:15:46 +02:00
|
|
|
OptionBinding *bind = bind_get(m, i);
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2017-12-28 02:35:53 +01:00
|
|
|
if(!bind) {
|
2012-08-16 18:15:46 +02:00
|
|
|
continue;
|
2017-12-28 02:35:53 +01:00
|
|
|
}
|
2017-02-11 02:24:47 +01:00
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
if(bind->type == BT_Resolution && video_query_capability(VIDEO_CAP_CHANGE_RESOLUTION) == VIDEO_AVAILABLE) {
|
2012-08-16 18:15:46 +02:00
|
|
|
if(bind->selected != -1) {
|
2020-04-16 18:25:54 +02:00
|
|
|
bool fullscreen = video_is_fullscreen();
|
2023-06-20 00:33:01 +02:00
|
|
|
VideoMode mode;
|
|
|
|
|
|
|
|
if(video_get_mode(bind->selected, fullscreen, &mode)) {
|
|
|
|
config_set_int(CONFIG_VID_WIDTH, mode.width);
|
|
|
|
config_set_int(CONFIG_VID_HEIGHT, mode.height);
|
|
|
|
change_vidmode = true;
|
|
|
|
}
|
2012-07-28 22:53:53 +02:00
|
|
|
}
|
|
|
|
}
|
2017-02-11 02:24:47 +01:00
|
|
|
|
2012-08-16 18:15:46 +02:00
|
|
|
bind_free(bind);
|
2023-01-09 04:19:31 +01:00
|
|
|
mem_free(bind);
|
2020-04-05 04:51:00 +02:00
|
|
|
});
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
|
2019-04-18 21:56:16 +02:00
|
|
|
if(change_vidmode) {
|
|
|
|
video_set_mode(
|
|
|
|
config_get_int(CONFIG_VID_DISPLAY),
|
|
|
|
config_get_int(CONFIG_VID_WIDTH),
|
|
|
|
config_get_int(CONFIG_VID_HEIGHT),
|
|
|
|
config_get_int(CONFIG_FULLSCREEN),
|
|
|
|
config_get_int(CONFIG_VID_RESIZABLE)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
if(m->context) {
|
|