Adapt for web

This commit is contained in:
Vladislav Khorev committed 2026-02-27 22:31:07 +03:00
1 parent 7418bbbe27
commit 9f82e7a2e6
14 files changed
+189 -40

No files matched your search

+93 -11
View File
@@ -5,15 +5,87 @@
#include <android/log.h>
#endif
#ifdef EMSCRIPTEN
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
// For Emscripten the game is heap-allocated so it can be destroyed and
// re-created when the WebGL context is lost and restored (e.g. fullscreen).
// For Android and Desktop a plain global value is used (no context loss).
#ifdef EMSCRIPTEN
ZL::Game* g_game = nullptr;
#else
ZL::Game game;
#endif
void MainLoop() {
#ifdef EMSCRIPTEN
if (g_game) g_game->update();
#else
game.update();
#endif
}
#ifdef EMSCRIPTEN
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
delete g_game;
g_game = nullptr;
return EM_TRUE;
}
EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
g_game = new ZL::Game();
g_game->setup();
return EM_TRUE;
}
// Resize the canvas, notify SDL, and push a synthetic SDL_WINDOWEVENT_RESIZED
// so Game::update()'s existing handler updates Environment::width/height and clears caches.
static void applyResize(int w, int h) {
if (w <= 0 || h <= 0) return;
// Resize the actual WebGL canvas — without this the rendered pixels stay at
// the original size no matter what Environment::width/height say.
emscripten_set_canvas_element_size("#canvas", w, h);
if (ZL::Environment::window)
SDL_SetWindowSize(ZL::Environment::window, w, h);
SDL_Event e = {};
e.type = SDL_WINDOWEVENT;
e.window.event = SDL_WINDOWEVENT_RESIZED;
e.window.data1 = w;
e.window.data2 = h;
SDL_PushEvent(&e);
}
EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*userData*/) {
// Use the event's window dimensions — querying the canvas element would
// return its old fixed size (e.g. 1280x720) before it has been resized.
applyResize(e->windowInnerWidth, e->windowInnerHeight);
return EM_FALSE;
}
EM_BOOL onFullscreenChanged(int /*eventType*/, const EmscriptenFullscreenChangeEvent* e, void* /*userData*/) {
if (e->isFullscreen) {
// e->screenWidth/screenHeight comes from screen.width/screen.height in JS,
// which on mobile browsers returns physical pixels (e.g. 2340x1080),
// causing the canvas to extend far off-screen. window.innerWidth/innerHeight
// always gives CSS logical pixels and is correct on both desktop and mobile.
int w = EM_ASM_INT({ return window.innerWidth; });
int h = EM_ASM_INT({ return window.innerHeight; });
applyResize(w, h);
}
// Exiting fullscreen: the browser fires a window resize event next,
// which onWindowResized handles automatically.
return EM_FALSE;
}
#endif
#ifdef __ANDROID__
extern "C" int SDL_main(int argc, char* argv[]) {
@@ -34,7 +106,7 @@ extern "C" int SDL_main(int argc, char* argv[]) {
__android_log_print(ANDROID_LOG_INFO, "Game", "Display resolution: %dx%d",
ZL::Environment::width, ZL::Environment::height);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
@@ -52,13 +124,13 @@ extern "C" int SDL_main(int argc, char* argv[]) {
ZL::Environment::width, ZL::Environment::height,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
if (!ZL::Environment::window) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "Failed to create window: %s", SDL_GetError());
SDL_Quit();
return 1;
}
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
if (!ctx) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_CreateContext failed: %s", SDL_GetError());
@@ -94,7 +166,7 @@ extern "C" int SDL_main(int argc, char* argv[]) {
}
return 0;
}
@@ -103,8 +175,8 @@ extern "C" int SDL_main(int argc, char* argv[]) {
int main(int argc, char *argv[]) {
try
{
constexpr int CONST_WIDTH = 1280;
constexpr int CONST_HEIGHT = 720;
@@ -142,6 +214,20 @@ int main(int argc, char *argv[]) {
SDL_GL_MakeCurrent(win, glContext);
ZL::Environment::window = win;
g_game = new ZL::Game();
g_game->setup();
// Re-create the game object when the WebGL context is lost and restored
// (this happens e.g. when the user toggles fullscreen in the browser).
emscripten_set_webglcontextlost_callback("#canvas", nullptr, EM_TRUE, onWebGLContextLost);
emscripten_set_webglcontextrestored_callback("#canvas", nullptr, EM_TRUE, onWebGLContextRestored);
// Keep Environment::width/height in sync when the canvas is resized.
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_FALSE, onWindowResized);
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_FALSE, onFullscreenChanged);
emscripten_set_main_loop(MainLoop, 0, 1);
#else
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
SDL_Log("SDL init failed: %s", SDL_GetError());
@@ -161,13 +247,9 @@ int main(int argc, char *argv[]) {
SDL_GLContext ctx = SDL_GL_CreateContext(ZL::Environment::window);
SDL_GL_MakeCurrent(ZL::Environment::window, ctx);
#endif
game.setup();
#ifdef EMSCRIPTEN
emscripten_set_main_loop(MainLoop, 0, 1);
#else
while (!game.shouldExit()) {
game.update();
SDL_Delay(2);
@@ -182,4 +264,4 @@ int main(int argc, char *argv[]) {
return 0;
}
#endif
#endif