Some clean up, web version prepare

This commit is contained in:
Vladislav Khorev committed 2026-07-17 21:27:47 +03:00
1 parent e9c888e2bf
commit 0975f3b9cd
104 files changed
+779 -1483

No files matched your search

+87 -77
View File
@@ -16,20 +16,41 @@
#endif
// Единый указатель на объект игры для всех платформ
FRG::Game* g_game = nullptr;
#if defined(EMSCRIPTEN)
static SDL_GLContext glContext_x;
static bool g_isFsLoaded = false; // Флаг готовности
// Макрос EMSCRIPTEN_KEEPALIVE экспортирует функцию в глобальный объект Module
extern "C" void EMSCRIPTEN_KEEPALIVE onFileSystemLoaded() {
// 1. Файлы загружены. Теперь можно читать настройки и логи
// Если функции readSettings() нет для Emscripten, форсируем логгер:
FRG::Environment::enableLogging = true;
FRG::initLogger();
FRG::logger() << "[boot] File system is ready. Setting up game..." << std::endl;
// 2. Инициализируем игру ТОЛЬКО когда файлы доступны
g_game = new FRG::Game();
g_game->setup();
// 3. Даем отмашку главному циклу
g_isFsLoaded = true;
}
#endif
// Единый указатель на объект игры для всех платформ
ZL::Game* g_game = nullptr;
void MainLoop() {
#if defined(EMSCRIPTEN)
// Крутим цикл вхолостую, пока JS читает IndexedDB
if (!g_isFsLoaded) return;
#endif
g_game->update();
}
#ifdef EMSCRIPTEN
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
@@ -55,8 +76,8 @@ static void applyResize(int logicalW, int logicalH) {
// Сообщаем SDL о новом размере.
// ВАЖНО: SDL2 в Emscripten ожидает здесь именно физические пиксели
// для корректной работы последующих вызовов glViewport.
if (ZL::Environment::window) {
SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH);
if (FRG::Environment::window) {
SDL_SetWindowSize(FRG::Environment::window, physicalW, physicalH);
}
// Пушим событие, чтобы движок пересчитал матрицы проекции
@@ -67,7 +88,7 @@ static void applyResize(int logicalW, int logicalH) {
e.window.data2 = physicalH;
SDL_PushEvent(&e);
logger() << "Resized, new size: " << logicalW << "x" << logicalH
FRG::logger() << "Resized, new size: " << logicalW << "x" << logicalH
<< " (physical: " << physicalW << "x" << physicalH
<< ", DPR: " << dpr << ")" << std::endl;
}
@@ -80,7 +101,7 @@ EM_BOOL onWindowResized(int /*eventType*/, const EmscriptenUiEvent* e, void* /*u
}
EM_BOOL onFullscreenChanged(int /*eventType*/, const EmscriptenFullscreenChangeEvent* e, void* /*userData*/) {
ZL::Environment::isFullscreen = e->isFullscreen;
FRG::Environment::isFullscreen = e->isFullscreen;
// Вместо window.innerWidth, попробуйте запросить размер целевого элемента
// так как после перехода в FS именно он растягивается на весь экран.
@@ -94,43 +115,32 @@ int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); // Для WebGL 2.0
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
ZL::Environment::window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
glContext_x = SDL_GL_CreateContext(ZL::Environment::window);
FRG::Environment::window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
glContext_x = SDL_GL_CreateContext(FRG::Environment::window);
SDL_GL_MakeCurrent(ZL::Environment::window, glContext_x);
g_game = new ZL::Game();
g_game->setup();
SDL_GL_MakeCurrent(FRG::Environment::window, glContext_x);
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);
// 2. ИНИЦИАЛИЗАЦИЯ РАЗМЕРОВ:
// Получаем реальные размеры окна браузера на момент запуска
int canvasW = EM_ASM_INT({ return window.innerWidth; });
int canvasH = EM_ASM_INT({ return window.innerHeight; });
// Вызываем вашу функцию — она сама применит DPR, выставит физический размер
// канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
applyResize(canvasW, canvasH);
// Prevent mouse clicks from generating fake SDL_FINGERDOWN events (desktop browser)
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
// Prevent touch events from generating fake SDL_MOUSEBUTTONDOWN events (mobile browser),
// since we now handle SDL_FINGERDOWN directly for multi-touch support.
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
ZL::emscriptenInitFileSystem();
// Запускаем асинхронное монтирование ФС
FRG::emscriptenInitFileSystem();
// Начинаем крутить пустой цикл. Он активируется, когда отработает onFileSystemLoaded
emscripten_set_main_loop(MainLoop, 0, 1);
return 0;
}
@@ -152,11 +162,11 @@ extern "C" int SDL_main(int argc, char* argv[]) {
SDL_Quit();
return 1;
}
ZL::Environment::width = displayMode.w;
ZL::Environment::height = displayMode.h;
FRG::Environment::width = displayMode.w;
FRG::Environment::height = displayMode.h;
__android_log_print(ANDROID_LOG_INFO, "Game", "Display resolution: %dx%d",
ZL::Environment::width, ZL::Environment::height);
FRG::Environment::width, FRG::Environment::height);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
@@ -169,31 +179,31 @@ extern "C" int SDL_main(int argc, char* argv[]) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
ZL::Environment::window = SDL_CreateWindow(
FRG::Environment::window = SDL_CreateWindow(
"Shadow Over Bishkek",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
ZL::Environment::width, ZL::Environment::height,
FRG::Environment::width, FRG::Environment::height,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
);
if (!ZL::Environment::window) {
if (!FRG::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);
SDL_GLContext ctx = SDL_GL_CreateContext(FRG::Environment::window);
if (!ctx) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_CreateContext failed: %s", SDL_GetError());
SDL_DestroyWindow(ZL::Environment::window);
SDL_DestroyWindow(FRG::Environment::window);
SDL_Quit();
return 1;
}
if (SDL_GL_MakeCurrent(ZL::Environment::window, ctx) != 0) {
if (SDL_GL_MakeCurrent(FRG::Environment::window, ctx) != 0) {
__android_log_print(ANDROID_LOG_ERROR, "Game", "SDL_GL_MakeCurrent failed: %s", SDL_GetError());
SDL_GL_DeleteContext(ctx);
SDL_DestroyWindow(ZL::Environment::window);
SDL_DestroyWindow(FRG::Environment::window);
SDL_Quit();
return 1;
}
@@ -232,20 +242,20 @@ extern "C" int SDL_main(int argc, char* argv[]) {
void readSettings()
{
const std::string settingsContent = ZL::readSavedTextFile("settings.json");
const std::string settingsContent = FRG::readSavedTextFile("settings.json");
if (!settingsContent.empty()) {
try {
const nlohmann::json settingsRoot = nlohmann::json::parse(settingsContent);
if (settingsRoot.contains("fullscreen")) {
ZL::Environment::isFullscreen = settingsRoot["fullscreen"].get<bool>();
FRG::Environment::isFullscreen = settingsRoot["fullscreen"].get<bool>();
}
if (settingsRoot.contains("isHighDPIEnabled")) {
ZL::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get<bool>();
FRG::Environment::isHighDPIEnabled = settingsRoot["isHighDPIEnabled"].get<bool>();
}
if (settingsRoot.contains("enableLogging")) {
ZL::Environment::enableLogging = settingsRoot["enableLogging"].get<bool>();
FRG::Environment::enableLogging = settingsRoot["enableLogging"].get<bool>();
}
}
@@ -262,12 +272,12 @@ int main(int argc, char* argv[]) {
try
{
readSettings();
if (ZL::Environment::enableLogging)
if (FRG::Environment::enableLogging)
{
ZL::initLogger();
FRG::initLogger();
}
ZL::logger() << "Log started!" << std::endl;
FRG::logger() << "Log started!" << std::endl;
#ifdef STEAMSDK
// Передаем явный App ID демо-версии
@@ -283,11 +293,11 @@ int main(int argc, char* argv[]) {
SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitorv2");
constexpr int CONST_WIDTH = ZL::Environment::CONST_DEFAULT_WIDTH;
constexpr int CONST_HEIGHT = ZL::Environment::CONST_DEFAULT_HEIGHT;
constexpr int CONST_WIDTH = FRG::Environment::CONST_DEFAULT_WIDTH;
constexpr int CONST_HEIGHT = FRG::Environment::CONST_DEFAULT_HEIGHT;
ZL::Environment::width = CONST_WIDTH;
ZL::Environment::height = CONST_HEIGHT;
FRG::Environment::width = CONST_WIDTH;
FRG::Environment::height = CONST_HEIGHT;
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
SDL_Log("SDL init failed: %s", SDL_GetError());
return 1;
@@ -298,53 +308,53 @@ int main(int argc, char* argv[]) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
if (ZL::Environment::isFullscreen) {
if (FRG::Environment::isFullscreen) {
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
}
SDL_DisplayMode dm;
if (SDL_GetCurrentDisplayMode(0, &dm) == 0) {
ZL::logger() << "Desktop resolution: " << dm.w << "x" << dm.h << " @ " << dm.refresh_rate << "Hz\n";
FRG::logger() << "Desktop resolution: " << dm.w << "x" << dm.h << " @ " << dm.refresh_rate << "Hz\n";
}
else {
SDL_Log("SDL_GetCurrentDisplayMode failed: %s", SDL_GetError());
}
int windowWidth = ZL::Environment::width;
int windowHeight = ZL::Environment::height;
int windowWidth = FRG::Environment::width;
int windowHeight = FRG::Environment::height;
if (dm.w <= 1280 && dm.h <= 720) {
windowWidth = round(dm.w / 1.5);
windowHeight = round(dm.h / 1.5);
}
ZL::Environment::window = SDL_CreateWindow(
FRG::Environment::window = SDL_CreateWindow(
"Shadow Over Bishkek Demo",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
windowWidth, windowHeight,
windowFlags
);
ctx = SDL_GL_CreateContext(ZL::Environment::window);
SDL_GL_MakeCurrent(ZL::Environment::window, ctx);
ctx = SDL_GL_CreateContext(FRG::Environment::window);
SDL_GL_MakeCurrent(FRG::Environment::window, ctx);
if (ZL::Environment::isHighDPIEnabled) {
if (FRG::Environment::isHighDPIEnabled) {
int drawW, drawH;
SDL_GL_GetDrawableSize(ZL::Environment::window, &drawW, &drawH);
ZL::Environment::width = drawW;
ZL::Environment::height = drawH;
ZL::logger() << "HiDPI enabled, drawable size: " << drawW << "x" << drawH << std::endl;
SDL_GL_GetDrawableSize(FRG::Environment::window, &drawW, &drawH);
FRG::Environment::width = drawW;
FRG::Environment::height = drawH;
FRG::logger() << "HiDPI enabled, drawable size: " << drawW << "x" << drawH << std::endl;
}
else {
int winW, winH;
SDL_GetWindowSize(ZL::Environment::window, &winW, &winH);
ZL::Environment::width = winW;
ZL::Environment::height = winH;
ZL::logger() << "HiDPI disabled, window size: " << winW << "x" << winH << std::endl;
SDL_GetWindowSize(FRG::Environment::window, &winW, &winH);
FRG::Environment::width = winW;
FRG::Environment::height = winH;
FRG::logger() << "HiDPI disabled, window size: " << winW << "x" << winH << std::endl;
}
// Динамическое создание объекта игры
g_game = new ZL::Game();
g_game = new FRG::Game();
g_game->setup();
while (!g_game->shouldExit()) {
@@ -356,10 +366,10 @@ int main(int argc, char* argv[]) {
#endif
}
//ZL::logger() << "Quitting step 1: " << std::endl;
//FRG::logger() << "Quitting step 1: " << std::endl;
// Явное уничтожение объекта игры ДО завершения работы Steamworks
delete g_game;
//ZL::logger() << "Quitting step 2: " << std::endl;
//FRG::logger() << "Quitting step 2: " << std::endl;
g_game = nullptr;
}
catch (const std::exception& e)
@@ -379,31 +389,31 @@ int main(int argc, char* argv[]) {
}
}
//ZL::logger() << "Quitting step 3: " << std::endl;
//FRG::logger() << "Quitting step 3: " << std::endl;
#ifdef STEAMSDK
// Деинициализация Steamworks происходит только тогда, когда все объекты игры гарантированно уничтожены
SteamAPI_Shutdown();
#endif
//ZL::logger() << "Quitting step 4: " << std::endl;
//FRG::logger() << "Quitting step 4: " << std::endl;
// Очистка ресурсов SDL
if (ctx) {
//ZL::logger() << "Quitting step 5: " << std::endl;
//FRG::logger() << "Quitting step 5: " << std::endl;
SDL_GL_DeleteContext(ctx);
}
//ZL::logger() << "Quitting step 6: " << std::endl;
if (ZL::Environment::window) {
//ZL::logger() << "Quitting step 7: " << std::endl;
SDL_DestroyWindow(ZL::Environment::window);
//FRG::logger() << "Quitting step 6: " << std::endl;
if (FRG::Environment::window) {
//FRG::logger() << "Quitting step 7: " << std::endl;
SDL_DestroyWindow(FRG::Environment::window);
}
//ZL::logger() << "Quitting step 8: " << std::endl;
//FRG::logger() << "Quitting step 8: " << std::endl;
#ifndef EMSCRIPTEN
// In Emscripten, SDL must stay alive across context loss/restore cycles
// so the window remains valid when the game object is re-created.
SDL_Quit();
#endif
//ZL::logger() << "Quitting step 9: " << std::endl;
//FRG::logger() << "Quitting step 9: " << std::endl;
return 0;
}
#endif