feat(main): activa SDL_MAIN_USE_CALLBACKS
main.cpp queda amb les 4 callbacks de SDL3: AppInit construeix el Director, AppEvent enruta cada event a handleEvent(), AppIterate crida iterate(), AppQuit reabsorbeix la propietat amb unique_ptr. El Director::run() i el bucle while interns desapareixen; el bootstrap de SDLManager/Audio/Context/DebugOverlay/Notifier viu ara al final del constructor. SDL_Quit() ja no es crida explícitament — SDL ho fa després de SDL_AppQuit.
This commit is contained in:
@@ -115,30 +115,72 @@ Director::Director(int argc, char* argv[])
|
||||
}
|
||||
|
||||
std::cout << '\n';
|
||||
|
||||
// === Bootstrap de finestra, audio i subsistemes de runtime ===
|
||||
|
||||
int initial_width = static_cast<int>(std::round(
|
||||
Defaults::Window::WIDTH * cfg_->window.zoom_factor));
|
||||
int initial_height = static_cast<int>(std::round(
|
||||
Defaults::Window::HEIGHT * cfg_->window.zoom_factor));
|
||||
|
||||
sdl_ = std::make_unique<SDLManager>(initial_width, initial_height, cfg_->window.fullscreen, *cfg_, [] { ConfigYaml::saveToFile(); });
|
||||
|
||||
// CRÍTIC: forçar ocultació del cursor DESPRÉS d'inicialitzar SDL,
|
||||
// perquè la creació de la finestra el reactiva.
|
||||
if (!cfg_->window.fullscreen) {
|
||||
Mouse::forceHide();
|
||||
}
|
||||
|
||||
const Audio::Config AUDIO_CONFIG{
|
||||
.enabled = Defaults::Audio::ENABLED,
|
||||
.volume = Defaults::Audio::VOLUME,
|
||||
.music_enabled = Defaults::Audio::MUSIC_ENABLED,
|
||||
.music_volume = Defaults::Audio::MUSIC_VOLUME,
|
||||
.sound_enabled = Defaults::Audio::SOUND_ENABLED,
|
||||
.sound_volume = Defaults::Audio::SOUND_VOLUME,
|
||||
};
|
||||
Audio::init(AUDIO_CONFIG);
|
||||
Audio::get()->applySettings(AUDIO_CONFIG);
|
||||
|
||||
AudioResource::getMusic("title.ogg");
|
||||
AudioResource::getMusic("game.ogg");
|
||||
if (cfg_->console) {
|
||||
std::cout << "Música precacheada\n";
|
||||
}
|
||||
|
||||
context_ = std::make_unique<SceneContext>();
|
||||
#ifdef _DEBUG
|
||||
context_->setNextScene(SceneType::TITLE);
|
||||
#else
|
||||
context_->setNextScene(SceneType::LOGO);
|
||||
#endif
|
||||
|
||||
debug_overlay_ = std::make_unique<System::DebugOverlay>(
|
||||
sdl_->getRenderer(),
|
||||
cfg_->rendering);
|
||||
|
||||
System::Notifier::init(sdl_->getRenderer());
|
||||
|
||||
last_ticks_ms_ = SDL_GetTicks();
|
||||
}
|
||||
|
||||
Director::~Director() {
|
||||
// Guardar opciones
|
||||
ConfigYaml::saveToFile();
|
||||
|
||||
// Destruir subsistemes en ordre invers a la construcció. Crític: el
|
||||
// renderer i la finestra (dins de sdl_) han de morir abans de cridar
|
||||
// SDL_Quit(). Si fossin destruïts pel destructor implícit del Director
|
||||
// morirïen DESPRÉS dels Input/Audio/SDL_Quit que vénen a sota.
|
||||
// Destruir subsistemes en ordre invers a la construcció. El Notifier
|
||||
// referencia el renderer, així que ha de morir abans que sdl_.
|
||||
// SDL_Quit() el crida SDL automàticament després de SDL_AppQuit; no
|
||||
// l'hem de cridar nosaltres.
|
||||
current_scene_.reset();
|
||||
debug_overlay_.reset();
|
||||
System::Notifier::destroy();
|
||||
context_.reset();
|
||||
sdl_.reset();
|
||||
|
||||
// Cleanup input
|
||||
Input::destroy();
|
||||
|
||||
// Cleanup audio
|
||||
Audio::destroy();
|
||||
|
||||
// Cleanup SDL
|
||||
SDL_Quit();
|
||||
|
||||
std::cout << "\nAdéu!\n";
|
||||
}
|
||||
|
||||
@@ -225,86 +267,6 @@ void Director::createSystemFolder(const std::string& folder) {
|
||||
}
|
||||
}
|
||||
|
||||
// Bucle principal del juego
|
||||
auto Director::run() -> int {
|
||||
// Calculate initial size from saved zoom_factor
|
||||
int initial_width = static_cast<int>(std::round(
|
||||
Defaults::Window::WIDTH * cfg_->window.zoom_factor));
|
||||
int initial_height = static_cast<int>(std::round(
|
||||
Defaults::Window::HEIGHT * cfg_->window.zoom_factor));
|
||||
|
||||
// Crear gestor SDL amb la engine_config + callback de persistència
|
||||
// per a quan toggleVSync (F4) muti vsync. Mantenim sdl_manager agnòstic.
|
||||
sdl_ = std::make_unique<SDLManager>(initial_width, initial_height, cfg_->window.fullscreen, *cfg_, [] { ConfigYaml::saveToFile(); });
|
||||
|
||||
// CRÍTIC: Forçar ocultació del cursor DESPRÉS de toda la inicialización SDL
|
||||
// Això evita que SDL mostre el cursor automàticament durante la creació de la finestra
|
||||
if (!cfg_->window.fullscreen) {
|
||||
Mouse::forceHide();
|
||||
}
|
||||
|
||||
// Inicializar sistema de audio (config inyectada desde Defaults)
|
||||
const Audio::Config AUDIO_CONFIG{
|
||||
.enabled = Defaults::Audio::ENABLED,
|
||||
.volume = Defaults::Audio::VOLUME,
|
||||
.music_enabled = Defaults::Audio::MUSIC_ENABLED,
|
||||
.music_volume = Defaults::Audio::MUSIC_VOLUME,
|
||||
.sound_enabled = Defaults::Audio::SOUND_ENABLED,
|
||||
.sound_volume = Defaults::Audio::SOUND_VOLUME,
|
||||
};
|
||||
Audio::init(AUDIO_CONFIG);
|
||||
Audio::get()->applySettings(AUDIO_CONFIG); // Aplicar volúmenes iniciales al motor
|
||||
|
||||
// Precachear música para evitar lag al empezar
|
||||
AudioResource::getMusic("title.ogg");
|
||||
AudioResource::getMusic("game.ogg");
|
||||
if (cfg_->console) {
|
||||
std::cout << "Música precacheada\n";
|
||||
}
|
||||
|
||||
// Crear context de escenes
|
||||
context_ = std::make_unique<SceneContext>();
|
||||
#ifdef _DEBUG
|
||||
context_->setNextScene(SceneType::TITLE);
|
||||
#else
|
||||
context_->setNextScene(SceneType::LOGO);
|
||||
#endif
|
||||
|
||||
// Overlay de debug (FPS + VSync). Vive en el Director porque es global
|
||||
// a todas las escenas. Toggle con F11 (visible por defecto en _DEBUG).
|
||||
debug_overlay_ = std::make_unique<System::DebugOverlay>(
|
||||
sdl_->getRenderer(),
|
||||
cfg_->rendering);
|
||||
|
||||
// Sistema de notificacions toast: singleton accessible des d'on calgui
|
||||
// (F1-F5 a sdl_manager, ESC a global_events). El renderer ha de viure
|
||||
// tant com el Notifier; el destruim explícitament abans de tornar.
|
||||
System::Notifier::init(sdl_->getRenderer());
|
||||
|
||||
// Comptador de delta time per al primer iterate().
|
||||
last_ticks_ms_ = SDL_GetTicks();
|
||||
|
||||
// Bucle principal: poll d'events + iterate() per frame. La primera escena
|
||||
// es construeix lazy dins d'iterate() via advanceScene(). En migrar a
|
||||
// SDL_MAIN_USE_CALLBACKS, aquest while desapareixerà i SDL_AppEvent/
|
||||
// SDL_AppIterate cridaran handleEvent()/iterate() directament.
|
||||
while (true) {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
SDL_AppResult r = handleEvent(event);
|
||||
if (r != SDL_APP_CONTINUE) {
|
||||
System::Notifier::destroy();
|
||||
return (r == SDL_APP_SUCCESS) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
SDL_AppResult r = iterate();
|
||||
if (r != SDL_APP_CONTINUE) {
|
||||
System::Notifier::destroy();
|
||||
return (r == SDL_APP_SUCCESS) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Director::buildScene(SceneType type, SDLManager& sdl, SceneContext& context)
|
||||
-> std::unique_ptr<Scene> {
|
||||
switch (type) {
|
||||
|
||||
@@ -23,9 +23,6 @@ class Director {
|
||||
Director(int argc, char* argv[]);
|
||||
~Director();
|
||||
|
||||
// Bucle principal del juego.
|
||||
auto run() -> int;
|
||||
|
||||
// Una iteració del bucle: pivot d'escena si cal, delta time, update i
|
||||
// render. Retorna SDL_APP_CONTINUE per seguir, SDL_APP_SUCCESS si vol
|
||||
// sortir net, SDL_APP_FAILURE si no es pot recuperar.
|
||||
|
||||
+29
-5
@@ -1,12 +1,36 @@
|
||||
// main.cpp - Punt d'entrada de l'aplicació
|
||||
// main.cpp - Punt d'entrada amb SDL_MAIN_USE_CALLBACKS
|
||||
// © 2026 JailDesigner
|
||||
//
|
||||
// El Director és EL programa: posseeix la configuració, els subsistemes i
|
||||
// el bucle. main.cpp només construeix el Director i delega.
|
||||
// l'estat. Aquestes 4 callbacks són la fontaneria mínima que SDL3 demana
|
||||
// per arrencar, processar events, iterar i tancar.
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "core/system/director.hpp"
|
||||
|
||||
auto main(int argc, char* argv[]) -> int {
|
||||
Director director(argc, argv);
|
||||
return director.run();
|
||||
auto SDL_AppInit(void** appstate, int argc, char* argv[]) -> SDL_AppResult {
|
||||
auto director = std::make_unique<Director>(argc, argv);
|
||||
*appstate = director.release();
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
auto SDL_AppEvent(void* appstate, SDL_Event* event) -> SDL_AppResult {
|
||||
auto* director = static_cast<Director*>(appstate);
|
||||
return director->handleEvent(*event);
|
||||
}
|
||||
|
||||
auto SDL_AppIterate(void* appstate) -> SDL_AppResult {
|
||||
auto* director = static_cast<Director*>(appstate);
|
||||
return director->iterate();
|
||||
}
|
||||
|
||||
void SDL_AppQuit(void* appstate, SDL_AppResult /*result*/) {
|
||||
// Reabsorbim la propietat: el destructor del Director allibera tot.
|
||||
std::unique_ptr<Director> director(static_cast<Director*>(appstate));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user