Fixing screen resize bugs

This commit is contained in:
Vladislav Khorev 2026-07-19 13:07:39 +03:00
parent 6406c4f258
commit 6a79e8e41e
3 changed files with 154 additions and 168 deletions

View File

@ -109,7 +109,7 @@ namespace FRG
renderer.shaderManager.AddShaderFromFiles("defaultColor", "resources/shaders/defaultColor.vertex", "resources/shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("defaultColor", "resources/shaders/defaultColor.vertex", "resources/shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("default", "resources/shaders/default.vertex", "resources/shaders/default_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("default", "resources/shaders/default.vertex", "resources/shaders/default_desktop.fragment", CONST_ZIP_FILE);
#endif #endif
loadingTexture = renderer.textureManager.LoadFromPng("resources/loading.png", ""); loadingTexture = renderer.textureManager.LoadFromPng("resources/loading003.png", "");
loadingProgressBarFrameTexture = renderer.textureManager.LoadFromPng( loadingProgressBarFrameTexture = renderer.textureManager.LoadFromPng(
"resources/loadingProgressBarFrame.png", "", true); "resources/loadingProgressBarFrame.png", "", true);
@ -1013,127 +1013,126 @@ namespace FRG
CheckGlError(__FILE__, __LINE__); CheckGlError(__FILE__, __LINE__);
} }
void Game::drawLoading() void Game::drawLoading()
{ {
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.RenderUniform1f("uAlpha", 1.0); renderer.RenderUniform1f("uAlpha", 1.0);
float width = Environment::projectionWidth; float width = Environment::projectionWidth;
float height = Environment::projectionHeight; float height = Environment::projectionHeight;
renderer.PushProjectionMatrix( renderer.PushProjectionMatrix(
-width * 0.5f, width * 0.5f, -width * 0.5f, width * 0.5f,
-height * 0.5f, height * 0.5f, -height * 0.5f, height * 0.5f,
-10, 10); -10, 10);
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); renderer.LoadIdentity();
if (showLoadingProgressBar == false) // Loading language screen if (showLoadingProgressBar == false) // Loading language screen
{ {
if (FRG::g_currentLanguage == FRG::Language::English) if (FRG::g_currentLanguage == FRG::Language::English)
{ {
glBindTexture(GL_TEXTURE_2D, menuManager.languageLoadingEn->getTexID()); glBindTexture(GL_TEXTURE_2D, menuManager.languageLoadingEn->getTexID());
} }
else if (FRG::g_currentLanguage == FRG::Language::Russian) else if (FRG::g_currentLanguage == FRG::Language::Russian)
{ {
glBindTexture(GL_TEXTURE_2D, menuManager.languageLoadingRu->getTexID()); glBindTexture(GL_TEXTURE_2D, menuManager.languageLoadingRu->getTexID());
} }
else else
{ {
glBindTexture(GL_TEXTURE_2D, loadingTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, loadingTexture->getTexID());
} }
} }
else else
{ {
glBindTexture(GL_TEXTURE_2D, loadingTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, loadingTexture->getTexID());
} }
renderer.DrawVertexRenderStruct(loadingMesh); renderer.DrawVertexRenderStruct(loadingMesh);
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
if (showLoadingProgressBar && loadingProgressBarFrameTexture && loadingProgressBarTexture) { if (showLoadingProgressBar && loadingProgressBarFrameTexture && loadingProgressBarTexture) {
const float W = Environment::projectionWidth; const float W = Environment::projectionWidth;
const float H = Environment::projectionHeight; const float H = Environment::projectionHeight;
static constexpr float kBarW = 400.0f; static constexpr float kBarW = 400.0f;
static constexpr float kBarH = 40.0f; static constexpr float kBarH = 40.0f;
const float barCenterY = -(H * 0.4f - 60.0f); const float barCenterY = -(H * 0.4f - 60.0f);
const float barLeft = -kBarW * 0.5f; const float barLeft = -kBarW * 0.5f;
const float barBottom = barCenterY - kBarH * 0.5f; const float barBottom = barCenterY - kBarH * 0.5f;
const float barTop = barCenterY + kBarH * 0.5f; const float barTop = barCenterY + kBarH * 0.5f;
// Rebuild frame mesh when projection dimensions change // Rebuild frame mesh when projection dimensions change
if (W != loadingBarLastW || H != loadingBarLastH) { if (W != loadingBarLastW || H != loadingBarLastH) {
loadingBarLastW = W; loadingBarLastW = W;
loadingBarLastH = H; loadingBarLastH = H;
VertexDataStruct frameData; VertexDataStruct frameData;
frameData.PositionData = { frameData.PositionData = {
{barLeft, barBottom, 4.f}, {barLeft, barTop, 4.f}, {barLeft+kBarW, barTop, 4.f}, {barLeft, barBottom, 4.f}, {barLeft, barTop, 4.f}, {barLeft+kBarW, barTop, 4.f},
{barLeft+kBarW, barTop, 4.f}, {barLeft+kBarW, barBottom, 4.f}, {barLeft, barBottom, 4.f} {barLeft+kBarW, barTop, 4.f}, {barLeft+kBarW, barBottom, 4.f}, {barLeft, barBottom, 4.f}
}; };
frameData.TexCoordData = { frameData.TexCoordData = {
{0.f,0.f},{0.f,1.f},{1.f,1.f}, {0.f,0.f},{0.f,1.f},{1.f,1.f},
{1.f,1.f},{1.f,0.f},{0.f,0.f} {1.f,1.f},{1.f,0.f},{0.f,0.f}
}; };
loadingProgressBarFrameMesh.data = std::move(frameData); loadingProgressBarFrameMesh.data = std::move(frameData);
loadingProgressBarFrameMesh.RefreshVBO(); loadingProgressBarFrameMesh.RefreshVBO();
loadingBarLastRenderedProgress = -1.0f; // force fill rebuild too loadingBarLastRenderedProgress = -1.0f; // force fill rebuild too
} }
// Rebuild fill mesh when progress changes // Rebuild fill mesh when progress changes
const float p = (std::min)(currentLoadingProgress(), 1.0f); const float p = (std::min)(currentLoadingProgress(), 1.0f);
if (p != loadingBarLastRenderedProgress) { if (p != loadingBarLastRenderedProgress) {
loadingBarLastRenderedProgress = p; loadingBarLastRenderedProgress = p;
if (p > 0.001f) { if (p > 0.001f) {
const float fillRight = barLeft + kBarW * p; const float fillRight = barLeft + kBarW * p;
VertexDataStruct fillData; VertexDataStruct fillData;
fillData.PositionData = { fillData.PositionData = {
{barLeft, barBottom, 4.f}, {barLeft, barTop, 4.f}, {fillRight, barTop, 4.f}, {barLeft, barBottom, 4.f}, {barLeft, barTop, 4.f}, {fillRight, barTop, 4.f},
{fillRight, barTop, 4.f}, {fillRight, barBottom, 4.f}, {barLeft, barBottom, 4.f} {fillRight, barTop, 4.f}, {fillRight, barBottom, 4.f}, {barLeft, barBottom, 4.f}
}; };
fillData.TexCoordData = { fillData.TexCoordData = {
{0.f,0.f},{0.f,1.f},{p,1.f}, {0.f,0.f},{0.f,1.f},{p,1.f},
{p,1.f},{p,0.f},{0.f,0.f} {p,1.f},{p,0.f},{0.f,0.f}
}; };
loadingProgressBarFillMesh.data = std::move(fillData); loadingProgressBarFillMesh.data = std::move(fillData);
loadingProgressBarFillMesh.RefreshVBO(); loadingProgressBarFillMesh.RefreshVBO();
} }
} }
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.RenderUniform1f("uAlpha", 1.0f); renderer.RenderUniform1f("uAlpha", 1.0f);
renderer.PushProjectionMatrix(-W*0.5f, W*0.5f, -H*0.5f, H*0.5f, -10, 10); renderer.PushProjectionMatrix(-W*0.5f, W*0.5f, -H*0.5f, H*0.5f, -10, 10);
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); renderer.LoadIdentity();
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, loadingProgressBarFrameTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, loadingProgressBarFrameTexture->getTexID());
renderer.DrawVertexRenderStruct(loadingProgressBarFrameMesh); renderer.DrawVertexRenderStruct(loadingProgressBarFrameMesh);
if (p > 0.001f) { if (p > 0.001f) {
glBindTexture(GL_TEXTURE_2D, loadingProgressBarTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, loadingProgressBarTexture->getTexID());
renderer.DrawVertexRenderStruct(loadingProgressBarFillMesh); renderer.DrawVertexRenderStruct(loadingProgressBarFillMesh);
} }
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
} }
CheckGlError(__FILE__, __LINE__);
}
CheckGlError(__FILE__, __LINE__);
}
int64_t Game::getSyncTimeMs() { int64_t Game::getSyncTimeMs() {
int64_t localNow = std::chrono::duration_cast<std::chrono::milliseconds>( int64_t localNow = std::chrono::duration_cast<std::chrono::milliseconds>(
@ -1189,6 +1188,35 @@ namespace FRG
SDL_GL_SwapWindow(FRG::Environment::window); SDL_GL_SwapWindow(FRG::Environment::window);
} }
void Game::onWindowResized() {
const bool wasPortrait = Environment::width < Environment::height;
if (Environment::isHighDPIEnabled) {
int drawW, drawH;
SDL_GL_GetDrawableSize(Environment::window, &drawW, &drawH);
Environment::width = drawW;
Environment::height = drawH;
}
else {
int winW, winH;
SDL_GetWindowSize(Environment::window, &winW, &winH);
Environment::width = winW / FRG::Environment::customDpiScale;
Environment::height = winH / FRG::Environment::customDpiScale;
}
Environment::computeProjectionDimensions();
const bool isPortrait = Environment::width < Environment::height;
menuManager.uiManager.updateAllLayouts();
menuManager.topUiManager.updateAllLayouts();
if (wasPortrait != isPortrait) {
menuManager.onOrientationChanged();
}
logger() << "Window resized (Render Size): " << Environment::width << "x" << Environment::height << std::endl;
}
void Game::update() { void Game::update() {
SDL_Event event; SDL_Event event;
const bool mobileIsPortrait = loadingCompleted && (Environment::width < Environment::height); const bool mobileIsPortrait = loadingCompleted && (Environment::width < Environment::height);
@ -1201,51 +1229,16 @@ namespace FRG
if (event.type == SDL_APP_WILLENTERBACKGROUND) { if (event.type == SDL_APP_WILLENTERBACKGROUND) {
isAppActive = false; isAppActive = false;
__android_log_print(ANDROID_LOG_INFO, "Game", "App moving to background, suspending loop"); __android_log_print(ANDROID_LOG_INFO, "Game", "App moving to background, suspending loop");
break;
} }
if (event.type == SDL_APP_DIDENTERFOREGROUND) { if (event.type == SDL_APP_DIDENTERFOREGROUND) {
isAppActive = true; isAppActive = true;
__android_log_print(ANDROID_LOG_INFO, "Game", "App returned to foreground, resuming loop"); __android_log_print(ANDROID_LOG_INFO, "Game", "App returned to foreground, resuming loop");
break;
} }
/*
__android_log_print(ANDROID_LOG_ERROR, "Game",
"Game::update step 1 event type: %d", event.type);
*/
#endif #endif
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { if (event.type == SDL_WINDOWEVENT && (event.window.event == SDL_WINDOWEVENT_RESIZED || event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)) {
const bool wasPortrait = Environment::width < Environment::height; onWindowResized();
FRG::logger() << "Window resized" << std::endl;
if (Environment::isHighDPIEnabled) {
// Если High DPI включен, запрашиваем реальное физическое разрешение буфера
int drawW, drawH;
SDL_GL_GetDrawableSize(Environment::window, &drawW, &drawH);
Environment::width = drawW;
Environment::height = drawH;
}
else {
// Если High DPI выключен, используем логические размеры из события
Environment::width = event.window.data1 / FRG::Environment::customDpiScale;
Environment::height = event.window.data2 / FRG::Environment::customDpiScale;
}
Environment::computeProjectionDimensions();
const bool isPortrait = Environment::width < Environment::height;
menuManager.uiManager.updateAllLayouts();
menuManager.topUiManager.updateAllLayouts();
if (wasPortrait != isPortrait) {
menuManager.onOrientationChanged();
}
logger() << "Window resized (Render Size): " << Environment::width << "x" << Environment::height << std::endl;
//space.clearTextRendererCache();
}
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
} }
// Suppress all input while portrait overlay is shown // Suppress all input while portrait overlay is shown
@ -1384,6 +1377,20 @@ namespace FRG
} }
} }
} }
// Fallback detection (proactive check)
int drawableW, drawableH;
SDL_GL_GetDrawableSize(Environment::window, &drawableW, &drawableH);
if (drawableW != lastDrawableW || drawableH != lastDrawableH) {
lastDrawableW = drawableW;
lastDrawableH = drawableH;
onWindowResized();
}
#ifdef __ANDROID__
if (!isAppActive) return;
#endif
// Drain one loading step per frame so the window/tab keeps pumping events // Drain one loading step per frame so the window/tab keeps pumping events
// and repainting between steps instead of freezing for the whole load. // and repainting between steps instead of freezing for the whole load.
if (!loadingCompleted && !loadSteps.empty()) { if (!loadingCompleted && !loadSteps.empty()) {

View File

@ -39,6 +39,7 @@ namespace FRG {
void setupPart2(); void setupPart2();
void update(); void update();
void render(); void render();
void onWindowResized();
bool shouldExit() const { return Environment::exitGameLoop; } bool shouldExit() const { return Environment::exitGameLoop; }
@ -201,6 +202,9 @@ namespace FRG {
int64_t newTickCount; int64_t newTickCount;
int64_t lastTickCount; int64_t lastTickCount;
int lastDrawableW = -1;
int lastDrawableH = -1;
static const size_t CONST_TIMER_INTERVAL = 10; static const size_t CONST_TIMER_INTERVAL = 10;
static const size_t CONST_MAX_TIME_INTERVAL = 1000; static const size_t CONST_MAX_TIME_INTERVAL = 1000;
}; };

View File

@ -267,34 +267,9 @@ int main(int argc, char* argv[]) {
} }
while (!g_game->shouldExit()) { while (!g_game->shouldExit()) {
SDL_Event event; g_game->update();
// Обрабатываем системные события Android до обновления кадра
/*while (SDL_PollEvent(&event)) {
// Перенаправляем событие в игру, чтобы сработал ваш внутренний цикл (память, ресайз и т.д.)
// Примечание: внутри Game::update у вас тоже стоит PollEvent.
// Чтобы события не терялись, лучше обрабатывать их в одном месте,
// но жизненно важные для ОС флаги перехватываем здесь:
if (event.type == SDL_QUIT) {
break;
}
// Сворачивание / Разворачивание приложения в Android if (!isAppActive) {
if (event.type == SDL_APP_WILLENTERBACKGROUND) {
isAppActive = false;
__android_log_print(ANDROID_LOG_INFO, "Game", "App moving to background, suspending loop");
}
if (event.type == SDL_APP_DIDENTERFOREGROUND) {
isAppActive = true;
__android_log_print(ANDROID_LOG_INFO, "Game", "App returned to foreground, resuming loop");
}
}*/
if (isAppActive) {
g_game->update();
// На Android шаг кадров завязан на VSync (SwapInterval = 1).
// SDL_Delay(16) здесь не нужен, он будет вызывать микро-фризы (stuttering).
}
else {
// Если игра свернута — спим, чтобы не нагружать CPU/GPU // Если игра свернута — спим, чтобы не нагружать CPU/GPU
SDL_Delay(100); SDL_Delay(100);
} }