Files
aee/source/core/system/director.hpp

74 lines
2.9 KiB
C++

#pragma once
#include <SDL3/SDL.h>
#include <atomic>
#include <cstdint>
// El Director és el thread principal que controla la presentació i els inputs.
// El codi del joc s'executa dins d'un *fiber* cooperatiu (veure fiber.hpp):
// el joc produeix un frame, crida JD8_Flip() que internament fa yield al
// Director, i el Director el presenta abans de tornar-lo a reprendre amb
// GameFiber::resume(). Tot ocorre en un únic thread — sense mutex, sense
// condition_variable, compatible amb el futur port a SDL_AppIterate.
class Director {
public:
static void init();
static void destroy();
static auto get() -> Director*;
// Bucle principal clàssic (build natiu sense SDL_MAIN_USE_CALLBACKS).
// Internament crida setup() + bucle d'iterate() + teardown(). Crida des de main().
void run();
// Punts d'entrada compatibles amb SDL_AppInit / SDL_AppIterate /
// SDL_AppEvent / SDL_AppQuit. Permeten que el Director siga driven
// per l'event loop de SDL3 en lloc d'un bucle propi — imprescindible
// per al port a emscripten, on el runtime posseïx el main loop.
void setup();
bool iterate(); // torna false quan el joc vol eixir
void teardown();
void handleEvent(const SDL_Event& event);
// Demana l'eixida (ex: segona pulsació d'ESC o SDL_QUIT)
void requestQuit();
auto isQuitRequested() const -> bool { return quit_requested_; }
// Consumeix el flag de "tecla polsada" (com l'antic JI_AnyKey)
auto consumeKeyPressed() -> bool;
// Indica si ESC està bloquejada (el joc no l'ha de veure)
auto isEscBlocked() const -> bool { return esc_blocked_ || esc_swallow_until_release_; }
// Pausa: mentre està activa, Director no fa resume() del fiber del joc,
// així que el joc queda congelat al seu últim JD8_Flip.
void togglePause();
auto isPaused() const -> bool { return paused_; }
private:
Director() = default;
~Director() = default;
static Director* instance_;
void pollAllEvents(); // drenatge amb SDL_PollEvent, només per al bucle natiu
// Buffers persistents entre iteracions. Abans eren locals a run(),
// ara són membres perquè iterate() els pot reutilitzar sense tornar-los
// a reservar en cada crida del callback.
Uint32 game_frame_[320 * 200]{};
Uint32 presentation_buffer_[320 * 200]{};
bool has_frame_{false};
std::atomic<bool> quit_requested_{false};
std::atomic<bool> key_pressed_{false};
std::atomic<bool> esc_blocked_{false};
std::atomic<bool> paused_{false};
// Quan el menú tanca amb ESC, empassem-nos l'ESC fins que l'usuari la deixe anar,
// per no fer eixir el joc al proper poll de JI_KeyPressed.
std::atomic<bool> esc_swallow_until_release_{false};
// Tecles consumides pel menú (KEY_DOWN): el KEY_UP associat cal empassar-lo
// per evitar que el joc (JI_AnyKey / JI_moveCheats) les veja quan el menú tanca.
bool menu_keys_held_[SDL_SCANCODE_COUNT]{};
};