Skip to content

Commit ce7e63f

Browse files
committed
port more special things to the web
1 parent ab15d62 commit ce7e63f

File tree

9 files changed

+205
-16
lines changed

9 files changed

+205
-16
lines changed

android/run-web.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ if [ $BUILD_SYSTEM = "meson" ]; then
2626

2727
export COMMON_EMSCRIPTEN_OPTIONS="'-fexceptions', '-sEXCEPTION_CATCHING_ALLOWED=[..]'"
2828

29+
# 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 library, which is a pain in the a**
2930
export LINK_EMSCRIPTEN_OPTIONS="$COMMON_EMSCRIPTEN_OPTIONS, '-sEXPORT_ALL=1', '-sUSE_GLFW=3', '-sUSE_WEBGPU=1', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sNO_EXIT_RUNTIME=0', '-sASSERTIONS=1'"
3031
export COMPILE_EMSCRIPTEN_OPTIONS="$COMMON_EMSCRIPTEN_OPTIONS"
3132

meson.build

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,20 @@ deps += dependency(
101101
default_options: sdl2_mixer_flags,
102102
)
103103

104+
if meson.is_cross_build() and host_machine.system() == 'emscripten'
105+
106+
# this is done here, since it's only needed for one file!
107+
cpp = meson.get_compiler('cpp')
108+
deps += cpp.find_library('embind', required: true)
109+
deps += cpp.find_library('openal', required: true)
110+
endif
104111

105112
## HEADER ONLY LIBS
106113
deps += dependency(
107114
'spdlog',
108115
required: true,
109116
native: native,
117+
version: '>=1.1.11',
110118
default_options: ['tests=false'],
111119
)
112120
deps += dependency('nlohmann_json', required: true, native: native)
@@ -137,6 +145,9 @@ deps += dependency(
137145

138146

139147
src_files = []
148+
link_args = []
149+
link_whole = []
150+
140151

141152
subdir('src')
142153

@@ -162,6 +173,8 @@ elif meson.is_cross_build() and host_machine.system() == 'emscripten'
162173
include_directories: inc_dirs,
163174
dependencies: deps,
164175
c_args: sdl2_mixer_defines,
176+
link_whole: link_whole,
177+
link_args: ['--preload-file', '../assets@/assets/'],
165178
cpp_args: compile_args + sdl2_mixer_defines,
166179
override_options: ['warning_level=3', 'werror=true'],
167180
native: native,

src/main.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <filesystem>
55
#if defined(__ANDROID__)
66
#include <spdlog/sinks/android_sink.h>
7+
#elif defined(__EMSCRIPTEN__)
8+
#include "web_utils.hpp"
79
#endif
810
#include <spdlog/sinks/basic_file_sink.h>
911
#include <spdlog/sinks/rotating_file_sink.h>
@@ -17,13 +19,22 @@ int main(int argc, char** argv) {
1719

1820
std::vector<spdlog::sink_ptr> sinks;
1921
#if defined(__ANDROID__)
22+
#define USE_FILE_LOG
2023
sinks.push_back(std::make_shared<spdlog::sinks::android_sink_mt>());
24+
#elif defined(__EMSCRIPTEN__)
25+
sinks.push_back(utils::get_web_sink());
2126
#else
27+
#define USE_FILE_LOG
2228
sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_st>());
2329
#endif
30+
31+
32+
#if defined(USE_FILE_LOG)
2433
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
2534
fmt::format("{}/oopetris.log", logs_path.string()), 1024 * 1024 * 10, 5, true
2635
));
36+
#endif
37+
2738
auto combined_logger = std::make_shared<spdlog::logger>("combined_logger", begin(sinks), end(sinks));
2839
spdlog::set_default_logger(combined_logger);
2940

src/music_manager.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ MusicManager::MusicManager(u8 channel_size)
2424
m_queued_music{ nullptr },
2525
m_channel_size{ channel_size },
2626
m_chunk_map{ std::unordered_map<std::string, Mix_Chunk*>{} } {
27+
28+
29+
//TODO: debug sound issues on EMSCRIPTEN
30+
#if not defined(__EMSCRIPTEN__)
31+
2732
Mix_Init(MIX_INIT_FLAC | MIX_INIT_MP3);
2833
const int result = SDL_InitSubSystem(SDL_INIT_AUDIO);
2934
if (result != 0) {
@@ -35,6 +40,8 @@ MusicManager::MusicManager(u8 channel_size)
3540
if (result != 0) {
3641
throw std::runtime_error{ "error on open the audio device: " + std::string{ Mix_GetError() } };
3742
}
43+
44+
#endif
3845
}
3946

4047
void MusicManager::hook_music_finished() {
@@ -63,7 +70,10 @@ void MusicManager::hook_music_finished() {
6370

6471

6572
tl::optional<std::string> MusicManager::load_and_play_music(const std::filesystem::path& location, const usize delay) {
73+
#if defined(__EMSCRIPTEN__)
74+
return "TODO: not implemented yet";
6675

76+
#endif
6777

6878
Mix_Music* music = Mix_LoadMUS(location.string().c_str());
6979
if (music == nullptr) {

src/spdlog/callback_sink.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2+
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3+
4+
5+
// FIXME: this is a temporary fix, since the spdlog upstream just added these 3 months ago, but didn't make a new release!!
6+
7+
#pragma once
8+
9+
#include <spdlog/details/null_mutex.h>
10+
#include <spdlog/sinks/base_sink.h>
11+
#include <spdlog/details/synchronous_factory.h>
12+
13+
#include <mutex>
14+
#include <string>
15+
16+
namespace spdlog {
17+
18+
// callbacks type
19+
typedef std::function<void(const details::log_msg &msg)> custom_log_callback;
20+
21+
namespace sinks {
22+
/*
23+
* Trivial callback sink, gets a callback function and calls it on each log
24+
*/
25+
template<typename Mutex>
26+
class callback_sink final : public base_sink<Mutex>
27+
{
28+
public:
29+
explicit callback_sink(const custom_log_callback &callback)
30+
: callback_{callback}
31+
{}
32+
33+
protected:
34+
void sink_it_(const details::log_msg &msg) override
35+
{
36+
callback_(msg);
37+
}
38+
void flush_() override{};
39+
40+
private:
41+
custom_log_callback callback_;
42+
};
43+
44+
using callback_sink_mt = callback_sink<std::mutex>;
45+
using callback_sink_st = callback_sink<details::null_mutex>;
46+
47+
} // namespace sinks
48+
49+
//
50+
// factory functions
51+
//
52+
template<typename Factory = spdlog::synchronous_factory>
53+
inline std::shared_ptr<logger> callback_logger_mt(const std::string &logger_name, const custom_log_callback &callback)
54+
{
55+
return Factory::template create<sinks::callback_sink_mt>(logger_name, callback);
56+
}
57+
58+
template<typename Factory = spdlog::synchronous_factory>
59+
inline std::shared_ptr<logger> callback_logger_st(const std::string &logger_name, const custom_log_callback &callback)
60+
{
61+
return Factory::template create<sinks::callback_sink_st>(logger_name, callback);
62+
}
63+
64+
} // namespace spdlog

src/tetris_application.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,11 @@ void TetrisApplication::render() const {
142142
void TetrisApplication::try_load_settings() {
143143
try {
144144
#if defined(__EMSCRIPTEN__)
145-
const std::string settings_string = utils::LocalStorage::get_item(settings_filename);
146-
m_settings = nlohmann::json::parse(settings_string);
145+
const auto settings_string = utils::LocalStorage::get_item(settings_filename);
146+
if (not settings_string.has_value()) {
147+
return;
148+
}
149+
m_settings = nlohmann::json::parse(settings_string.value());
147150
#else
148151
m_settings = nlohmann::json::parse(settings_file);
149152
#endif

src/utils.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ namespace utils {
4242
throw std::runtime_error{ "Failed in getting the Pref Path: " + std::string{ SDL_GetError() } };
4343
}
4444
return std::filesystem::path{ std::string{ pref_path } };
45+
#elif defined(__EMSCRIPTEN__)
46+
return std::filesystem::path{ "/" };
4547
#else
48+
4649
// this is only used in local build for debugging, when compiling in release mode the path is real path where the app can store many things without interfering with other things (eg. AppData\Roaming\... onw Windows or .local/share/... on Linux )
4750
return std::filesystem::path{ "." };
4851
#endif
@@ -63,6 +66,8 @@ namespace utils {
6366
// if you build in BUILD_INSTALLER mode, you have to assure that the data is there eg. music + fonts!
6467
#endif
6568
return std::filesystem::path{ std::string{ resource_path } } / "assets";
69+
#elif defined(__EMSCRIPTEN__)
70+
return std::filesystem::path{ "/assets" };
6671
#else
6772
return std::filesystem::path{ "assets" };
6873
#endif

src/web_utils.cpp

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,110 @@
11

22
#if defined(__EMSCRIPTEN__)
33
#include "web_utils.hpp"
4-
#include <emscripten.h>
4+
#include <emscripten/val.h>
5+
#include <memory>
6+
// FIXME: this is a temporary fix, since the spdlog upstream just added these 3 months ago, but didn't make a new release!!
7+
#include "spdlog/callback_sink.h"
58
#include <string>
69
#include <tl/optional.hpp>
710

811
tl::optional<std::string> utils::LocalStorage::get_item(const std::string& key) {
912

10-
1113
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
1214

13-
emscripten::val value localStorage.getItem(key.c_str());
15+
emscripten::val value = localStorage.call<emscripten::val>("getItem", emscripten::val{ key });
1416

15-
if (value.isUndefined()) {
17+
if (value.isNull()) {
1618
return tl::nullopt;
1719
}
1820

19-
return value.as<std::string | undefined>();
21+
return value.as<std::string>();
2022
}
2123

2224
void utils::LocalStorage::set_item(const std::string& key, const std::string& value) {
2325

2426
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
2527

26-
localStorage.setItem(key.c_str(), value.c_str());
28+
localStorage.call<void>("setItem", emscripten::val{ key }, emscripten::val{ value });
2729
}
2830

2931
void utils::LocalStorage::remove_item(const std::string& key) {
3032

3133
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
3234

33-
localStorage.removeItem(key.c_str());
35+
localStorage.call<void>("removeItem", emscripten::val{ key });
3436
}
3537

3638
void utils::LocalStorage::clear() {
3739

3840
thread_local const emscripten::val localStorage = emscripten::val::global("localStorage");
3941

40-
localStorage.clear();
42+
localStorage.call<void>("clear");
43+
}
44+
45+
46+
void utils::console::error(const std::string& message) {
47+
thread_local const emscripten::val console = emscripten::val::global("console");
48+
console.call<void>("error", emscripten::val{ message });
49+
}
50+
51+
void utils::console::warn(const std::string& message) {
52+
thread_local const emscripten::val console = emscripten::val::global("console");
53+
console.call<void>("warn", emscripten::val{ message });
54+
}
55+
56+
void utils::console::log(const std::string& message) {
57+
thread_local const emscripten::val console = emscripten::val::global("console");
58+
console.call<void>("log", emscripten::val{ message });
59+
}
60+
61+
void utils::console::info(const std::string& message) {
62+
thread_local const emscripten::val console = emscripten::val::global("console");
63+
console.call<void>("info", emscripten::val{ message });
64+
}
65+
66+
void utils::console::debug(const std::string& message) {
67+
thread_local const emscripten::val console = emscripten::val::global("console");
68+
console.call<void>("debug", emscripten::val{ message });
69+
}
70+
71+
void utils::console::trace(const std::string& message) {
72+
thread_local const emscripten::val console = emscripten::val::global("console");
73+
console.call<void>("trace", emscripten::val{ message });
74+
}
75+
76+
void utils::console::clear() {
77+
thread_local const emscripten::val console = emscripten::val::global("console");
78+
console.call<void>("clear");
79+
}
80+
81+
std::shared_ptr<spdlog::sinks::callback_sink_mt> utils::get_web_sink() {
82+
return std::make_shared<spdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg& msg) {
83+
const auto message = std::string{ msg.payload.begin(), msg.payload.end() };
84+
85+
switch (msg.level) {
86+
case spdlog::level::off:
87+
return;
88+
case spdlog::level::trace:
89+
utils::console::trace(message);
90+
break;
91+
case spdlog::level::debug:
92+
utils::console::debug(message);
93+
break;
94+
case spdlog::level::info:
95+
utils::console::info(message);
96+
break;
97+
case spdlog::level::warn:
98+
utils::console::warn(message);
99+
break;
100+
case spdlog::level::err:
101+
case spdlog::level::critical:
102+
utils::console::error(message);
103+
break;
104+
default:
105+
return;
106+
}
107+
});
41108
}
42109

43110

src/web_utils.hpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,39 @@
22

33
#pragma once
44

5-
#include <string>
6-
#include <tl/optional.hpp>
7-
8-
95
#if not defined(__EMSCRIPTEN__)
106
#error this header is for emscripten only
117
#endif
128

13-
namespace utils {
9+
#include <memory>
10+
#include <string>
11+
#include <tl/optional.hpp>
12+
// FIXME: this is a temporary fix, since the spdlog upstream just added these 3 months ago, but didn't make a new release!!
13+
#include "spdlog/callback_sink.h"
1414

15+
namespace utils {
1516

1617
struct LocalStorage {
1718

18-
static tl::optional<std::string> [[nodiscard]] get_item(const std::string& key);
19+
[[nodiscard]] static tl::optional<std::string> get_item(const std::string& key);
1920
static void set_item(const std::string& key, const std::string& value);
2021
static void remove_item(const std::string& key);
2122
static void clear();
2223
};
2324

25+
[[nodiscard]] std::shared_ptr<spdlog::sinks::callback_sink_mt> get_web_sink();
26+
27+
28+
namespace console {
29+
void clear();
30+
//TODO, these support more arguments, write templates for that
31+
void error(const std::string& message);
32+
void warn(const std::string& message);
33+
void log(const std::string& message);
34+
void info(const std::string& message);
35+
void debug(const std::string& message);
36+
void trace(const std::string& message);
37+
}; // namespace console
38+
2439

2540
}; // namespace utils

0 commit comments

Comments
 (0)