Skip to content

Commit 8cabcfb

Browse files
committed
fix: fix multiple issues with emscripten
support NOT prerendred text, so that no texture is created in a pthread correctly exit in the cases, where it is needed correctly stub out local storage, and the music manager
1 parent 19ba113 commit 8cabcfb

File tree

8 files changed

+117
-29
lines changed

8 files changed

+117
-29
lines changed

platforms/build-web.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ export PACKAGE_FLAGS="'--use-port=sdl2', '--use-port=harfbuzz', '--use-port=free
6262

6363
export COMMON_FLAGS="'-fexceptions', '-pthread', '-sUSE_PTHREADS=1', '-sEXCEPTION_CATCHING_ALLOWED=[..]', $PACKAGE_FLAGS"
6464

65-
# TODO see if ALLOW_MEMORY_GROWTH is needed, but if we load ttf's and music it likely is and we don't have to debug OOm crahses, that aren't handled by some thrid party library, which is painful
66-
export LINK_FLAGS="$COMMON_FLAGS, '-sEXPORT_ALL=1', '-sUSE_WEBGPU=1', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sASSERTIONS=1','-sERROR_ON_UNDEFINED_SYMBOLS=1', '-sFETCH=1'"
65+
# TODO see if ALLOW_MEMORY_GROWTH is needed, but if we load ttf's and music it likely is and we don't have to debug OOm crashes, that aren't handled by some third party library, which is painful
66+
export LINK_FLAGS="$COMMON_FLAGS, '-sEXPORT_ALL=1', '-sUSE_WEBGPU=1', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sASSERTIONS=1','-sERROR_ON_UNDEFINED_SYMBOLS=1', '-sFETCH=1', '-sEXIT_RUNTIME=1'"
6767
export COMPILE_FLAGS="$COMMON_FLAGS ,'-DAUDIO_PREFER_MP3'"
6868

6969
export CROSS_FILE="./platforms/crossbuild-web.ini"
@@ -110,7 +110,7 @@ cpp_link_args = [$LINK_FLAGS]
110110
needs_exe_wrapper = true
111111
sys_root = '$EMSCRIPTEN_SYS_ROOT'
112112
113-
APP_ROMFS='$ROMFS'
113+
APP_ROMFS='$ROMFS/assets/'
114114
115115
EOF
116116

src/executables/game/application.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ void Application::load_emscripten() {
129129

130130
const auto duration = std::chrono::milliseconds(SDL_GetTicks64() - m_loading_info->start_time());
131131

132-
// we can reach this via SDL_QUIT, SDL_APP_TERMINATING or (not console::inMainLoop())
132+
// we can reach this via SDL_QUIT or SDL_APP_TERMINATING
133133
if (not m_loading_info->m_finished_loading or not m_is_running) {
134134

135135
spdlog::debug("Aborted loading after {}", duration);
@@ -464,6 +464,7 @@ void Application::initialize() {
464464
this->load_resources();
465465

466466
#if !defined(NDEBUG)
467+
//TODO(Totto): emscripten: this is using sdl rendering (to a texture) in another thread then the main thread, use proxying to the main thread here too, and disable OOPETRIS_DONT_USE_PRERENDERED_TEXT
467468
m_fps_text = std::make_unique<ui::Label>(
468469
this, "FPS: ?", font_manager().get(FontId::Default), Color::white(),
469470
std::pair<double, double>{ 0.95, 0.95 },
@@ -563,6 +564,7 @@ void Application::load_resources() {
563564
{ FontId::NotoColorEmoji, "NotoColorEmoji.ttf" },
564565
{ FontId::Symbola, "Symbola.ttf" }
565566
};
567+
566568
for (const auto& [font_id, path] : fonts) {
567569
const auto font_path = utils::get_assets_folder() / "fonts" / path;
568570
m_font_manager->load(font_id, font_path, fonts_size);

src/executables/meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ if build_application
5353
)
5454
endif
5555

56+
if not APP_ROMFS.endswith('/')
57+
APP_ROMFS = APP_ROMFS + '/'
58+
endif
59+
5660
emscripten_link_args += ['--preload-file', APP_ROMFS + '@/assets/']
5761

5862
endif

src/graphics/text.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,34 @@
33
#include "manager/service_provider.hpp"
44

55

6+
#if defined(OOPETRIS_DONT_USE_PRERENDERED_TEXT)
7+
8+
Text::Text(
9+
const ServiceProvider* service_provider,
10+
const std::string& text,
11+
const Font& font,
12+
const Color& color,
13+
const shapes::URect& dest
14+
)
15+
: m_font{ font },
16+
m_color{ color },
17+
m_dest{ dest },
18+
m_text{ text } {
19+
UNUSED(service_provider);
20+
}
21+
22+
23+
void Text::render(const ServiceProvider& service_provider) const {
24+
auto texture = service_provider.renderer().prerender_text(m_text, m_font, m_color);
25+
service_provider.renderer().draw_texture(texture, m_dest);
26+
}
27+
28+
void Text::set_text(const ServiceProvider& service_provider, const std::string& text) {
29+
UNUSED(service_provider);
30+
m_text = text;
31+
}
32+
33+
#else
634
Text::Text(
735
const ServiceProvider* service_provider,
836
const std::string& text,
@@ -23,3 +51,5 @@ void Text::render(const ServiceProvider& service_provider) const {
2351
void Text::set_text(const ServiceProvider& service_provider, const std::string& text) {
2452
m_text = service_provider.renderer().prerender_text(text, m_font, m_color);
2553
}
54+
55+
#endif

src/graphics/text.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@
88
#include "rect.hpp"
99
#include "texture.hpp"
1010

11+
//TODO: set this flag in the build system, or maybe also fix https://github.com/OpenBrickProtocolFoundation/oopetris/issues/132 in the process
12+
#if defined(__EMSCRIPTEN__)
13+
#define OOPETRIS_DONT_USE_PRERENDERED_TEXT
14+
#endif
15+
16+
1117
struct Text final {
1218
private:
1319
Font m_font;
1420
Color m_color;
1521
shapes::URect m_dest;
22+
#if defined(OOPETRIS_DONT_USE_PRERENDERED_TEXT)
23+
std::string m_text;
24+
#else
1625
Texture m_text;
17-
26+
#endif
1827
public:
1928
OOPETRIS_GRAPHICS_EXPORTED Text(
2029
const ServiceProvider* service_provider,

src/helper/graphic_utils.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
#include "graphic_utils.hpp"
33
#include <exception>
44

5+
#if defined(__EMSCRIPTEN__)
6+
#include <emscripten.h>
7+
#endif
8+
59
SDL_Color utils::sdl_color_from_color(const Color& color) {
610
return SDL_Color{ color.r, color.g, color.b, color.a };
711
}
@@ -185,6 +189,8 @@ void utils::exit(int status_code) {
185189
// but is required here
186190
// see: https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md
187191
throw utils::ExitException{ status_code };
192+
#elif defined(__EMSCRIPTEN__)
193+
emscripten_force_exit(status_code);
188194
#else
189195
std::exit(status_code);
190196
#endif

src/helper/web_utils.cpp

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,69 @@
99
#include <memory>
1010
#include <string>
1111

12-
std::optional<std::string> web::LocalStorage::get_item(const std::string& key) {
12+
namespace {
13+
14+
emscripten::val get_local_storage() {
15+
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
16+
return localStorage;
17+
}
18+
19+
[[maybe_unused]] std::optional<std::string> get_item_impl(const std::string& key) {
1320

14-
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
21+
thread_local const emscripten::val localStorage = get_local_storage();
1522

16-
emscripten::val value = localStorage.call<emscripten::val>("getItem", emscripten::val{ key });
23+
emscripten::val value = localStorage.call<emscripten::val>("getItem", emscripten::val{ key });
1724

18-
if (value.isNull()) {
19-
return std::nullopt;
25+
if (value.isNull()) {
26+
return std::nullopt;
27+
}
28+
29+
return value.as<std::string>();
2030
}
2131

22-
return value.as<std::string>();
23-
}
32+
[[maybe_unused]] void set_item_impl(const std::string& key, const std::string& value) {
2433

25-
void web::LocalStorage::set_item(const std::string& key, const std::string& value) {
34+
thread_local const emscripten::val localStorage = get_local_storage();
2635

27-
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
36+
localStorage.call<void>("setItem", emscripten::val{ key }, emscripten::val{ value });
37+
}
2838

29-
localStorage.call<void>("setItem", emscripten::val{ key }, emscripten::val{ value });
30-
}
39+
[[maybe_unused]] void remove_item_impl(const std::string& key) {
3140

32-
void web::LocalStorage::remove_item(const std::string& key) {
41+
thread_local const emscripten::val localStorage = get_local_storage();
42+
43+
localStorage.call<void>("removeItem", emscripten::val{ key });
44+
}
45+
46+
[[maybe_unused]] void clear_impl() {
3347

34-
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
48+
thread_local const emscripten::val localStorage = get_local_storage();
3549

36-
localStorage.call<void>("removeItem", emscripten::val{ key });
50+
localStorage.call<void>("clear");
51+
}
52+
53+
} // namespace
54+
55+
std::optional<std::string> web::LocalStorage::get_item(const std::string& key) {
56+
// we don't have access to the localStorage in threads (Web workers)
57+
//TODO: if we are in the main thread, call the impl directly, otherwise use proxying
58+
(void) (key);
59+
return std::nullopt;
3760
}
3861

39-
void web::LocalStorage::clear() {
62+
void web::LocalStorage::set_item(const std::string& key, const std::string& value) {
63+
//TODO:
64+
(void) (key);
65+
(void) (value);
66+
}
4067

41-
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
68+
void web::LocalStorage::remove_item(const std::string& key) {
69+
//TODO:
70+
(void) (key);
71+
}
4272

43-
localStorage.call<void>("clear");
73+
void web::LocalStorage::clear() {
74+
//TODO:
4475
}
4576

4677

@@ -57,18 +88,16 @@ void web::console::log(const std::string& message) {
5788
}
5889

5990
void web::console::info(const std::string& message) {
60-
thread_local const emscripten::val console = emscripten::val::global("console");
61-
console.call<void>("info", emscripten::val{ message });
91+
emscripten_console_log(message.c_str());
6292
}
6393

6494
void web::console::debug(const std::string& message) {
65-
thread_local const emscripten::val console = emscripten::val::global("console");
66-
console.call<void>("debug", emscripten::val{ message });
95+
// NOTE: really the console, but also debug output
96+
emscripten_dbg(message.c_str());
6797
}
6898

6999
void web::console::trace(const std::string& message) {
70-
thread_local const emscripten::val console = emscripten::val::global("console");
71-
console.call<void>("trace", emscripten::val{ message });
100+
emscripten_console_trace(message.c_str());
72101
}
73102

74103
void web::console::clear() {

src/manager/music_manager.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,22 @@ MusicManager::MusicManager(ServiceProvider* service_provider, u8 channel_size)
5656
}
5757
}
5858

59+
#if defined(__EMSCRIPTEN__)
60+
//TODO: do we need this, first do this:
61+
// https://github.com/libsdl-org/SDL/issues/6385
62+
#else
63+
const auto audio_channels = 2;
64+
5965
// 2 here means STEREO, note that channels above means tracks, e.g. simultaneous playing source that are mixed,
6066
// hence the name SDL2_mixer
6167
const auto audio_result =
62-
Mix_OpenAudio(constants::audio_frequency, MIX_DEFAULT_FORMAT, 2, constants::audio_chunk_size);
68+
Mix_OpenAudio(constants::audio_frequency, MIX_DEFAULT_FORMAT, audio_channels, constants::audio_chunk_size);
69+
6370

6471
if (audio_result != 0) {
6572
throw helper::InitializationError{ fmt::format("Failed to open an audio device: {}", SDL_GetError()) };
6673
}
74+
#endif
6775

6876
m_s_instance = this;
6977

0 commit comments

Comments
 (0)