From 2728ca9646a720798b684fc55f7a2ad56bb2f233 Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sat, 28 Feb 2026 20:37:47 +0300 Subject: [PATCH] Adapting web version --- proj-web/space-game001plain.html | 164 ++++++++---------- resources/Cargo_Base_color_sRGB.png | 4 +- resources/DefaultMaterial_BaseColor_shine.png | 3 - resources/MainCharacter_Base_color_sRGB.png | 4 +- resources/game_over/Container.png | 4 +- resources/game_over/Filledbuttons.png | 4 +- resources/game_over/FinalScore.png | 4 +- resources/game_over/MissionFailed.png | 4 +- resources/game_over/Secondarybutton.png | 4 +- src/Environment.cpp | 20 +++ src/Environment.h | 9 +- src/Game.cpp | 87 +++++----- src/Space.cpp | 54 +++--- src/UiManager.cpp | 2 +- src/main.cpp | 67 ++++--- src/render/TextRenderer.cpp | 7 +- 16 files changed, 234 insertions(+), 207 deletions(-) delete mode 100644 resources/DefaultMaterial_BaseColor_shine.png diff --git a/proj-web/space-game001plain.html b/proj-web/space-game001plain.html index 17708db..72892cd 100644 --- a/proj-web/space-game001plain.html +++ b/proj-web/space-game001plain.html @@ -1,100 +1,76 @@ - - + + + + + + Space Game + + + + +
Downloading...
+ - - - - Space Game - - - - -
-
-
- - - - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/resources/Cargo_Base_color_sRGB.png b/resources/Cargo_Base_color_sRGB.png index 6ec9e8e..58aee2f 100644 --- a/resources/Cargo_Base_color_sRGB.png +++ b/resources/Cargo_Base_color_sRGB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6bd5d071ed94f2bd8ce3ab060136e9b93b04b06d5eabaffc7845a99d73faeb30 -size 2345111 +oid sha256:88a34dad270df316707d8492823653a4c3143ee948f6c3fcdca232fa3f27a184 +size 2577457 diff --git a/resources/DefaultMaterial_BaseColor_shine.png b/resources/DefaultMaterial_BaseColor_shine.png deleted file mode 100644 index 53e6f41..0000000 --- a/resources/DefaultMaterial_BaseColor_shine.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:26c118a182e269aebfa22684489836d8632b0b2cb6631be646c2678c18493463 -size 90539 diff --git a/resources/MainCharacter_Base_color_sRGB.png b/resources/MainCharacter_Base_color_sRGB.png index 73d132c..ba3e58c 100644 --- a/resources/MainCharacter_Base_color_sRGB.png +++ b/resources/MainCharacter_Base_color_sRGB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dc8c7262949a4f2f86d2cc47daf572d908294868d89f7577a771149c7e2e60e5 -size 1296067 +oid sha256:6e49da5723497cd4bf152d5f3fd99608f597f2dc3646c05fb478507f36b89697 +size 1669304 diff --git a/resources/game_over/Container.png b/resources/game_over/Container.png index 226e276..e2af5b9 100644 --- a/resources/game_over/Container.png +++ b/resources/game_over/Container.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d495f21543ab72e6a2cb5082507212616c666bef11bc99bd0447e6906a957836 -size 6709 +oid sha256:4292ab255136aeeff003e265bfde42bef4aabb092427bd68f9b2ac42d86916a1 +size 27198 diff --git a/resources/game_over/Filledbuttons.png b/resources/game_over/Filledbuttons.png index 808344f..a9b2806 100644 --- a/resources/game_over/Filledbuttons.png +++ b/resources/game_over/Filledbuttons.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6283a169f71822d3c3f8b3c80369cd3ac25b70ef51d3f34685687b1d2819a1b -size 2406 +oid sha256:436d9137c479b475d8bc753961986ea3f58b6a2439de6f83b5d707172c3f2ff9 +size 7976 diff --git a/resources/game_over/FinalScore.png b/resources/game_over/FinalScore.png index 7ac0bbc..af06f07 100644 --- a/resources/game_over/FinalScore.png +++ b/resources/game_over/FinalScore.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6bb6e8e59482729d6da84188c830842cf07e4e379076ba64d7916b8b0d45cf09 -size 1244 +oid sha256:ea4e2a8408fa1b68793fd8d81135902ff15ef2779ea898a99a9ef83ff6e147e8 +size 4142 diff --git a/resources/game_over/MissionFailed.png b/resources/game_over/MissionFailed.png index 1a8731d..ec8d6c3 100644 --- a/resources/game_over/MissionFailed.png +++ b/resources/game_over/MissionFailed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:930565f3911bcb11904808fe67ca278c1460f42f7c7c7dcfffc2301f5c0d408c -size 2678 +oid sha256:c2187818c1fbfb127f70c130f033aa7c16cc3b3a02a2ea59317413437f530c30 +size 9982 diff --git a/resources/game_over/Secondarybutton.png b/resources/game_over/Secondarybutton.png index 5bb684a..37cdae0 100644 --- a/resources/game_over/Secondarybutton.png +++ b/resources/game_over/Secondarybutton.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00a1c3c32da992686febd87918801868d4af2ec99904ed3f80b0c8f58009c5b2 -size 1840 +oid sha256:113c524330190fbdf36f0f7b4ebfc03032170aff5011f8c17201533b52db872f +size 5387 diff --git a/src/Environment.cpp b/src/Environment.cpp index 1fec925..9c41b4d 100644 --- a/src/Environment.cpp +++ b/src/Environment.cpp @@ -36,5 +36,25 @@ ClientState Environment::shipState; const float Environment::CONST_Z_NEAR = 5.f; const float Environment::CONST_Z_FAR = 5000.f; +float Environment::projectionWidth = 1280.0f; +float Environment::projectionHeight = 720.0f; + +void Environment::computeProjectionDimensions() +{ + if (width <= 0 || height <= 0) return; + + const float refShortSide = 720.0f; + float aspect = (float)width / (float)height; + + if (width >= height) { + // Landscape: fix height to 720, scale width to preserve aspect + projectionHeight = refShortSide; + projectionWidth = refShortSide * aspect; + } else { + // Portrait: fix width to 720, scale height to preserve aspect + projectionWidth = refShortSide; + projectionHeight = refShortSide / aspect; + } +} } // namespace ZL diff --git a/src/Environment.h b/src/Environment.h index 5d3c1ca..17125ac 100644 --- a/src/Environment.h +++ b/src/Environment.h @@ -35,8 +35,15 @@ public: static const float CONST_Z_NEAR; static const float CONST_Z_FAR; + // Virtual projection dimensions used for all 2D/UI rendering. + // These maintain the screen's actual aspect ratio but normalize the + // height to 720 (landscape) or width to 720 (portrait), giving a + // consistent coordinate space regardless of physical screen resolution. + static float projectionWidth; + static float projectionHeight; - + // Call this once at startup and whenever the window is resized. + static void computeProjectionDimensions(); }; } // namespace ZL diff --git a/src/Game.cpp b/src/Game.cpp index e653d94..253b475 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -83,6 +83,8 @@ namespace ZL void Game::setup() { glContext = SDL_GL_CreateContext(ZL::Environment::window); + Environment::computeProjectionDimensions(); + ZL::BindOpenGlFunctions(); ZL::CheckGlError(); renderer.InitOpenGL(); @@ -99,7 +101,7 @@ namespace ZL loadingTexture = std::make_unique(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE)); #endif - loadingMesh.data = CreateRect2D({ Environment::width * 0.5, Environment::height * 0.5 }, { Environment::width * 0.5, Environment::height*0.5 }, 3); + loadingMesh.data = CreateRect2D({ Environment::projectionWidth * 0.5f, Environment::projectionHeight * 0.5f }, { Environment::projectionWidth * 0.5f, Environment::projectionHeight * 0.5f }, 3); loadingMesh.RefreshVBO(); #ifdef EMSCRIPTEN @@ -141,17 +143,14 @@ namespace ZL Environment::shipState.nickname = nickname; Environment::shipState.shipType = shipType; - networkClient = std::make_unique(); + auto localClient = new LocalClient; + ClientState st = Environment::shipState; + st.id = localClient->GetClientId(); + localClient->setLocalPlayerState(st); + + networkClient = std::unique_ptr(localClient); networkClient->Connect("", 0); -#ifndef NETWORK - auto localClient = dynamic_cast(networkClient.get()); - if (localClient) { - ZL::ClientState st = Environment::shipState; - st.id = localClient->GetClientId(); - localClient->setLocalPlayerState(st); - } -#endif lastTickCount = 0; spaceGameStarted = 1; }; @@ -160,8 +159,7 @@ namespace ZL Environment::shipState.nickname = nickname; Environment::shipState.shipType = shipType; - networkClient = std::make_unique(); -#ifdef NETWORK + #ifdef EMSCRIPTEN networkClient = std::make_unique(); networkClient->Connect("localhost", 8081); @@ -169,19 +167,6 @@ namespace ZL networkClient = std::make_unique(taskManager.getIOContext()); networkClient->Connect("localhost", 8081); #endif -#else - networkClient->Connect("", 0); -#endif - -#ifndef NETWORK - auto localClient = dynamic_cast(networkClient.get()); - if (localClient) { - ZL::ClientState st = Environment::shipState; - st.id = localClient->GetClientId(); - localClient->setLocalPlayerState(st); - } -#endif - if (networkClient) { std::string joinMsg = std::string("JOIN:") + nickname + ":" + std::to_string(shipType); @@ -264,8 +249,8 @@ namespace ZL renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vTexCoordName); - float width = Environment::width; - float height = Environment::height; + float width = Environment::projectionWidth; + float height = Environment::projectionHeight; renderer.PushProjectionMatrix( 0, width, @@ -350,16 +335,18 @@ namespace ZL if (event.type == SDL_QUIT) { Environment::exitGameLoop = true; } -#if SDL_VERSION_ATLEAST(2,0,5) - else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { + + + if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { // Обновляем размеры и сбрасываем кеш текстов, т.к. меши хранятся в пикселях Environment::width = event.window.data1; Environment::height = event.window.data2; - std::cout << "Window resized: " << Environment::width << "x" << Environment::height << std::endl; + Environment::computeProjectionDimensions(); + std::cout << "Window resized: " << Environment::width << "x" << Environment::height << std::endl; space.clearTextRendererCache(); } -#endif + #ifdef __ANDROID__ if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_AC_BACK) { Environment::exitGameLoop = true; @@ -368,22 +355,38 @@ namespace ZL #ifdef __ANDROID__ if (event.type == SDL_FINGERDOWN) { - int mx = static_cast(event.tfinger.x * Environment::width); - int my = static_cast(event.tfinger.y * Environment::height); + int mx = static_cast(event.tfinger.x * Environment::projectionWidth); + int my = static_cast(event.tfinger.y * Environment::projectionHeight); handleDown(mx, my); } else if (event.type == SDL_FINGERUP) { - int mx = static_cast(event.tfinger.x * Environment::width); - int my = static_cast(event.tfinger.y * Environment::height); + int mx = static_cast(event.tfinger.x * Environment::projectionWidth); + int my = static_cast(event.tfinger.y * Environment::projectionHeight); handleUp(mx, my); } else if (event.type == SDL_FINGERMOTION) { - int mx = static_cast(event.tfinger.x * Environment::width); - int my = static_cast(event.tfinger.y * Environment::height); + int mx = static_cast(event.tfinger.x * Environment::projectionWidth); + int my = static_cast(event.tfinger.y * Environment::projectionHeight); handleMotion(mx, my); } #else - if (event.type == SDL_MOUSEBUTTONDOWN) { + + + if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) { + // Преобразуем экранные пиксели в проекционные единицы + int mx = static_cast((float)event.button.x / Environment::width * Environment::projectionWidth); + int my = static_cast((float)event.button.y / Environment::height * Environment::projectionHeight); + + if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(mx, my); + else handleUp(mx, my); + } + else if (event.type == SDL_MOUSEMOTION) { + int mx = static_cast((float)event.motion.x / Environment::width * Environment::projectionWidth); + int my = static_cast((float)event.motion.y / Environment::height * Environment::projectionHeight); + handleMotion(mx, my); + } + + /*if (event.type == SDL_MOUSEBUTTONDOWN) { int mx = event.button.x; int my = event.button.y; handleDown(mx, my); @@ -397,7 +400,7 @@ namespace ZL int mx = event.motion.x; int my = event.motion.y; handleMotion(mx, my); - } + }*/ if (event.type == SDL_MOUSEWHEEL) { static const float zoomstep = 2.0f; @@ -454,7 +457,7 @@ namespace ZL void Game::handleDown(int mx, int my) { int uiX = mx; - int uiY = Environment::height - my; + int uiY = Environment::projectionHeight - my; menuManager.uiManager.onMouseDown(uiX, uiY); @@ -482,7 +485,7 @@ namespace ZL void Game::handleUp(int mx, int my) { int uiX = mx; - int uiY = Environment::height - my; + int uiY = Environment::projectionHeight - my; menuManager.uiManager.onMouseUp(uiX, uiY); @@ -497,7 +500,7 @@ namespace ZL void Game::handleMotion(int mx, int my) { int uiX = mx; - int uiY = Environment::height - my; + int uiY = Environment::projectionHeight - my; menuManager.uiManager.onMouseMove(uiX, uiY); diff --git a/src/Space.cpp b/src/Space.cpp index 146d7bc..ba82066 100644 --- a/src/Space.cpp +++ b/src/Space.cpp @@ -159,15 +159,15 @@ namespace ZL // В пределах экрана? // (можно оставить, можно клампить) - float sx = (ndc.x() * 0.5f + 0.5f) * Environment::width; - float sy = (ndc.y() * 0.5f + 0.5f) * Environment::height; + float sx = (ndc.x() * 0.5f + 0.5f) * Environment::projectionWidth; + float sy = (ndc.y() * 0.5f + 0.5f) * Environment::projectionHeight; outX = sx; outY = sy; // Можно отсеять те, что вне: - if (sx < -200 || sx > Environment::width + 200) return false; - if (sy < -200 || sy > Environment::height + 200) return false; + if (sx < -200 || sx > Environment::projectionWidth + 200) return false; + if (sy < -200 || sy > Environment::projectionHeight + 200) return false; return true; } @@ -296,12 +296,12 @@ namespace ZL cubemapTexture = std::make_shared( std::array{ - CreateTextureDataFromPng("resources/sky/space_red.png", CONST_ZIP_FILE), - CreateTextureDataFromPng("resources/sky/space_red.png", CONST_ZIP_FILE), - CreateTextureDataFromPng("resources/sky/space_red.png", CONST_ZIP_FILE), - CreateTextureDataFromPng("resources/sky/space_red.png", CONST_ZIP_FILE), - CreateTextureDataFromPng("resources/sky/space_red.png", CONST_ZIP_FILE), - CreateTextureDataFromPng("resources/sky/space_red.png", CONST_ZIP_FILE) + CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE), + CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE), + CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE), + CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE), + CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE), + CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE) }); @@ -859,8 +859,8 @@ namespace ZL // если ничего не изменилось — не трогаем VBO if (crosshairMeshValid && - crosshairLastW == Environment::width && - crosshairLastH == Environment::height && + crosshairLastW == Environment::projectionWidth && + crosshairLastH == Environment::projectionHeight && std::abs(crosshairLastAlpha - crosshairCfg.alpha) < 1e-6f && std::abs(crosshairLastThickness - crosshairCfg.thicknessPx) < 1e-6f && std::abs(crosshairLastGap - crosshairCfg.gapPx) < 1e-6f && @@ -869,18 +869,18 @@ namespace ZL return; } - crosshairLastW = Environment::width; - crosshairLastH = Environment::height; + crosshairLastW = Environment::projectionWidth; + crosshairLastH = Environment::projectionHeight; crosshairLastAlpha = crosshairCfg.alpha; crosshairLastThickness = crosshairCfg.thicknessPx; crosshairLastGap = crosshairCfg.gapPx; crosshairLastScaleMul = crosshairCfg.scaleMul; - float cx = Environment::width * 0.5f; - float cy = Environment::height * 0.5f; + float cx = Environment::projectionWidth * 0.5f; + float cy = Environment::projectionHeight * 0.5f; // масштаб от reference (стандартно: по высоте) - float scale = (crosshairCfg.refH > 0) ? (Environment::height / (float)crosshairCfg.refH) : 1.0f; + float scale = (crosshairCfg.refH > 0) ? (Environment::projectionHeight / (float)crosshairCfg.refH) : 1.0f; scale *= crosshairCfg.scaleMul; float thickness = crosshairCfg.thicknessPx * scale; @@ -940,7 +940,7 @@ namespace ZL glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); renderer.shaderManager.PushShader("defaultColor"); - renderer.PushProjectionMatrix((float)Environment::width, (float)Environment::height, 0.f, 1.f); + renderer.PushProjectionMatrix(Environment::projectionWidth, Environment::projectionHeight, 0.f, 1.f); renderer.PushMatrix(); renderer.LoadIdentity(); @@ -1187,15 +1187,15 @@ namespace ZL // 4) Настройки стиля Eigen::Vector4f enemyColor(1.f, 0.f, 0.f, 1.f); // красный - float thickness = 10.0f; // толщина линий (px) + float thickness = 2.0f; // толщина линий (px) float z = 0.0f; // 2D слой // 5) Если цель в кадре: рисуем скобки if (onScreen) { // перевод NDC -> экран (в пикселях) - float sx = (ndcX * 0.5f + 0.5f) * Environment::width; - float sy = (ndcY * 0.5f + 0.5f) * Environment::height; + float sx = (ndcX * 0.5f + 0.5f) * Environment::projectionWidth; + float sy = (ndcY * 0.5f + 0.5f) * Environment::projectionHeight; // анимация “снаружи внутрь” // targetAcquireAnim растёт к 1, быстро (похоже на захват) @@ -1234,7 +1234,7 @@ namespace ZL glClear(GL_DEPTH_BUFFER_BIT); renderer.shaderManager.PushShader("defaultColor"); - renderer.PushProjectionMatrix((float)Environment::width, (float)Environment::height, 0.f, 1.f); + renderer.PushProjectionMatrix(Environment::projectionWidth, Environment::projectionHeight, 0.f, 1.f); renderer.PushMatrix(); renderer.LoadIdentity(); @@ -1248,8 +1248,8 @@ namespace ZL float leadNdcX, leadNdcY, leadNdcZ, leadClipW; if (projectToNDC(leadWorld, leadNdcX, leadNdcY, leadNdcZ, leadClipW) && leadClipW > 0.0f) { if (leadNdcX >= -1 && leadNdcX <= 1 && leadNdcY >= -1 && leadNdcY <= 1) { - float lx = (leadNdcX * 0.5f + 0.5f) * Environment::width; - float ly = (leadNdcY * 0.5f + 0.5f) * Environment::height; + float lx = (leadNdcX * 0.5f + 0.5f) * Environment::projectionWidth; + float ly = (leadNdcY * 0.5f + 0.5f) * Environment::projectionHeight; float distLead = (Environment::shipState.position - leadWorld).norm(); float r = 30.0f / (distLead * 0.01f + 1.0f); @@ -1323,8 +1323,8 @@ namespace ZL float edgeNdcX = dirX * k; float edgeNdcY = dirY * k; - float edgeX = (edgeNdcX * 0.5f + 0.5f) * Environment::width; - float edgeY = (edgeNdcY * 0.5f + 0.5f) * Environment::height; + float edgeX = (edgeNdcX * 0.5f + 0.5f) * Environment::projectionWidth; + float edgeY = (edgeNdcY * 0.5f + 0.5f) * Environment::projectionHeight; float bob = std::sin(t * 6.0f) * 6.0f; edgeX += dirX * bob; @@ -1367,7 +1367,7 @@ namespace ZL glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); renderer.shaderManager.PushShader("defaultColor"); - renderer.PushProjectionMatrix((float)Environment::width, (float)Environment::height, 0.f, 1.f); + renderer.PushProjectionMatrix(Environment::projectionWidth, Environment::projectionHeight, 0.f, 1.f); renderer.PushMatrix(); renderer.LoadIdentity(); diff --git a/src/UiManager.cpp b/src/UiManager.cpp index 647d72f..6b3dc95 100644 --- a/src/UiManager.cpp +++ b/src/UiManager.cpp @@ -657,7 +657,7 @@ namespace ZL { } void UiManager::draw(Renderer& renderer) { - renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1); + renderer.PushProjectionMatrix(Environment::projectionWidth, Environment::projectionHeight, -1, 1); renderer.PushMatrix(); renderer.LoadIdentity(); diff --git a/src/main.cpp b/src/main.cpp index d1bdc1e..6b62092 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,20 +44,34 @@ EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void 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); +static void applyResize(int logicalW, int logicalH) { + // Получаем коэффициент плотности пикселей (например, 2.625 на Pixel или 3.0 на Samsung) + double dpr = emscripten_get_device_pixel_ratio(); + + // Вычисляем реальные физические пиксели + int physicalW = static_cast(logicalW * dpr); + int physicalH = static_cast(logicalH * dpr); + + // Устанавливаем размер внутреннего буфера канваса + emscripten_set_canvas_element_size("#canvas", physicalW, physicalH); + + // Сообщаем SDL о новом размере. + // ВАЖНО: SDL2 в Emscripten ожидает здесь именно физические пиксели + // для корректной работы последующих вызовов glViewport. + if (ZL::Environment::window) { + SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH); + } + + // Обновляем ваши внутренние переменные окружения + ZL::Environment::width = physicalW; + ZL::Environment::height = physicalH; + + // Пушим событие, чтобы движок пересчитал матрицы проекции SDL_Event e = {}; e.type = SDL_WINDOWEVENT; e.window.event = SDL_WINDOWEVENT_RESIZED; - e.window.data1 = w; - e.window.data2 = h; + e.window.data1 = physicalW; + e.window.data2 = physicalH; SDL_PushEvent(&e); } @@ -69,17 +83,11 @@ EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*u } 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. + // Вместо window.innerWidth, попробуйте запросить размер целевого элемента + // так как после перехода в FS именно он растягивается на весь экран. + double clientW, clientH; + emscripten_get_element_css_size("#canvas", &clientW, &clientH); + applyResize(clientW, clientH); return EM_FALSE; } @@ -226,6 +234,21 @@ int main(int argc, char *argv[]) { // 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); + + // 2. ИНИЦИАЛИЗАЦИЯ РАЗМЕРОВ: + // Получаем реальные размеры окна браузера на момент запуска + int canvasW = EM_ASM_INT({ return window.innerWidth; }); + int canvasH = EM_ASM_INT({ return window.innerHeight; }); + + // Вызываем вашу функцию — она сама применит DPR, выставит физический размер + // канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции. + applyResize(canvasW, canvasH); + + // 3. Создаем игру и вызываем setup (теперь проекция уже будет знать верный size) + g_game = new ZL::Game(); + g_game->setup(); + + SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); emscripten_set_main_loop(MainLoop, 0, 1); #else diff --git a/src/render/TextRenderer.cpp b/src/render/TextRenderer.cpp index 585ca8d..73e2db1 100644 --- a/src/render/TextRenderer.cpp +++ b/src/render/TextRenderer.cpp @@ -362,9 +362,10 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca // 4. Рендеринг r->shaderManager.PushShader(shaderName); - // Матрица проекции (экрана) - float W = (float)Environment::width; - float H = (float)Environment::height; + // Матрица проекции — используем виртуальные проекционные размеры, + // чтобы координаты текста были независимы от физического разрешения экрана. + float W = Environment::projectionWidth; + float H = Environment::projectionHeight; Eigen::Matrix4f proj = Eigen::Matrix4f::Identity(); proj(0, 0) = 2.0f / W; proj(1, 1) = 2.0f / H;