// Port a l'API de callbacks de SDL3: el runtime posseïx el main loop i ens // crida a SDL_AppInit/SDL_AppIterate/SDL_AppEvent/SDL_AppQuit. Imprescindible // per al port a emscripten on no podem tindre un bucle while propi al hilo // principal. Funciona igual en build natiu (Linux/macOS/Windows) perquè // SDL3 embolcalla el seu propi main loop darrere d'aquestes callbacks. #define SDL_MAIN_USE_CALLBACKS #include #include #include #include #include "core/input/key_config.hpp" #include "core/jail/jail_audio.hpp" #include "core/jail/jdraw8.hpp" #include "core/jail/jfile.hpp" #include "core/jail/jgame.hpp" #include "core/locale/locale.hpp" #include "core/rendering/menu.hpp" #include "core/rendering/overlay.hpp" #include "core/rendering/screen.hpp" #include "core/resources/resource_helper.hpp" #include "core/system/director.hpp" #include "game/options.hpp" SDL_AppResult SDL_AppInit(void** /*appstate*/, int /*argc*/, char* /*argv*/[]) { srand(unsigned(time(nullptr))); // Crea la carpeta de configuració i carrega les opcions file_setconfigfolder("jailgames/aee"); // Ruta absoluta a data/ basada en la ubicació de l'executable. // SDL_GetBasePath() detecta automàticament si estem dins d'un .app bundle // (retorna Contents/Resources/) o en un executable normal (carpeta del binari). const char* base_path = SDL_GetBasePath(); std::string resource_pack_path; if (base_path) { const std::string data_path = std::string(base_path) + "data/"; file_setresourcefolder(data_path.c_str()); resource_pack_path = std::string(base_path) + "resources.pack"; } else { resource_pack_path = "resources.pack"; } // Sistema de recursos: prova el pack i cau a fitxers solts dins data/. // Release natiu exigix el pack (sense fallback); Debug i WASM mantenen // el fallback actiu per a desenvolupament i per al build amb MEMFS. #if defined(NDEBUG) && !defined(__EMSCRIPTEN__) const bool enable_fallback = false; #else const bool enable_fallback = true; #endif if (!ResourceHelper::initializeResourceSystem(resource_pack_path, enable_fallback)) { return SDL_APP_FAILURE; } Options::setConfigFile(std::string(file_getconfigfolder()) + "config.yaml"); Options::loadFromFile(); // KeyConfig: defaults des de data/input/keys.yaml + overrides de l'usuari KeyConfig::init("input/keys.yaml", std::string(file_getconfigfolder()) + "keys.yaml"); #ifndef NDEBUG // debug.yaml: estat inicial de gameplay per a tests ràpids, // només en builds de debug. Options::setDebugFile(std::string(file_getconfigfolder()) + "debug.yaml"); Options::loadDebugFromFile(); #endif #ifdef __EMSCRIPTEN__ // MEMFS no persistix entre recàrregues: força valors sensats per a web. Options::window.fullscreen = false; Options::window.zoom = 1; Options::video.aspect_ratio_4_3 = true; Options::video.scaling_mode = Options::ScalingMode::INTEGER; Options::video.texture_filter = Options::TextureFilter::LINEAR; #endif // Carrega textos (idioma per defecte: valencià) Locale::load("locale/ca.yaml"); // Carrega presets de shaders Options::setPostFXFile(std::string(file_getconfigfolder()) + "postfx.yaml"); Options::loadPostFXFromFile(); Options::setCrtPiFile(std::string(file_getconfigfolder()) + "crtpi.yaml"); Options::loadCrtPiFromFile(); JG_Init(); Screen::init(); JD8_Init(); JA_Init(48000, SDL_AUDIO_S16, 2); Options::applyAudio(); Overlay::init(); Menu::init(); Director::init(); Director::get()->setup(); return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void* /*appstate*/) { // Una iteració del bucle del Director. Abans els events es drenaven // amb SDL_PollEvent dins d'aquesta funció; ara SDL ens els lliura // d'un en un via SDL_AppEvent, així que iterate() no els toca. if (!Director::get()->iterate()) { return SDL_APP_SUCCESS; } return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppEvent(void* /*appstate*/, SDL_Event* event) { if (!event) return SDL_APP_CONTINUE; Director::get()->handleEvent(*event); if (Director::get()->isQuitRequested()) { return SDL_APP_SUCCESS; } return SDL_APP_CONTINUE; } void SDL_AppQuit(void* /*appstate*/, SDL_AppResult /*result*/) { // Neteja en ordre invers al de SDL_AppInit. Director::get()->teardown(); Options::saveToFile(); KeyConfig::saveOverrides(); #ifndef NDEBUG Options::saveDebugToFile(); #endif Director::destroy(); KeyConfig::destroy(); Menu::destroy(); Overlay::destroy(); JA_Quit(); JD8_Quit(); Screen::destroy(); JG_Finalize(); ResourceHelper::shutdownResourceSystem(); }