clang-format
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
BasedOnStyle: Google
|
BasedOnStyle: Google
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
IndentAccessModifiers: true
|
NamespaceIndentation: All
|
||||||
|
IndentAccessModifiers: false
|
||||||
ColumnLimit: 0 # Sin límite de longitud de línea
|
ColumnLimit: 0 # Sin límite de longitud de línea
|
||||||
BreakBeforeBraces: Attach # Llaves en la misma línea
|
BreakBeforeBraces: Attach # Llaves en la misma línea
|
||||||
AllowShortIfStatementsOnASingleLine: true
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
|||||||
@@ -5,93 +5,93 @@
|
|||||||
|
|
||||||
// --- Clase Audio: gestor de audio (singleton) ---
|
// --- Clase Audio: gestor de audio (singleton) ---
|
||||||
class Audio {
|
class Audio {
|
||||||
public:
|
public:
|
||||||
// --- Enums ---
|
// --- Enums ---
|
||||||
enum class Group : int {
|
enum class Group : int {
|
||||||
ALL = -1, // Todos los grupos
|
ALL = -1, // Todos los grupos
|
||||||
GAME = 0, // Sonidos del juego
|
GAME = 0, // Sonidos del juego
|
||||||
INTERFACE = 1 // Sonidos de la interfaz
|
INTERFACE = 1 // Sonidos de la interfaz
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MusicState {
|
enum class MusicState {
|
||||||
PLAYING, // Reproduciendo música
|
PLAYING, // Reproduciendo música
|
||||||
PAUSED, // Música pausada
|
PAUSED, // Música pausada
|
||||||
STOPPED, // Música detenida
|
STOPPED, // Música detenida
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr float MAX_VOLUME = 1.0F; // Volumen máximo
|
static constexpr float MAX_VOLUME = 1.0F; // Volumen máximo
|
||||||
static constexpr float MIN_VOLUME = 0.0F; // Volumen mínimo
|
static constexpr float MIN_VOLUME = 0.0F; // Volumen mínimo
|
||||||
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
||||||
|
|
||||||
// --- Singleton ---
|
// --- Singleton ---
|
||||||
static void init(); // Inicializa el objeto Audio
|
static void init(); // Inicializa el objeto Audio
|
||||||
static void destroy(); // Libera el objeto Audio
|
static void destroy(); // Libera el objeto Audio
|
||||||
static auto get() -> Audio*; // Obtiene el puntero al objeto Audio
|
static auto get() -> Audio*; // Obtiene el puntero al objeto Audio
|
||||||
Audio(const Audio&) = delete; // Evitar copia
|
Audio(const Audio&) = delete; // Evitar copia
|
||||||
auto operator=(const Audio&) -> Audio& = delete; // Evitar asignación
|
auto operator=(const Audio&) -> Audio& = delete; // Evitar asignación
|
||||||
|
|
||||||
static void update(); // Actualización del sistema de audio
|
static void update(); // Actualización del sistema de audio
|
||||||
|
|
||||||
// --- Control de música ---
|
// --- Control de música ---
|
||||||
void playMusic(const std::string& name, int loop = -1); // Reproducir música en bucle
|
void playMusic(const std::string& name, int loop = -1); // Reproducir música en bucle
|
||||||
void pauseMusic(); // Pausar reproducción de música
|
void pauseMusic(); // Pausar reproducción de música
|
||||||
void resumeMusic(); // Continua la música pausada
|
void resumeMusic(); // Continua la música pausada
|
||||||
void stopMusic(); // Detener completamente la música
|
void stopMusic(); // Detener completamente la música
|
||||||
void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música
|
void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música
|
||||||
|
|
||||||
// --- Control de sonidos ---
|
// --- Control de sonidos ---
|
||||||
void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre
|
void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre
|
||||||
void playSound(struct JA_Sound_t* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero
|
void playSound(struct JA_Sound_t* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero
|
||||||
void stopAllSounds() const; // Detener todos los sonidos
|
void stopAllSounds() const; // Detener todos los sonidos
|
||||||
|
|
||||||
// --- Control de volumen ---
|
// --- Control de volumen ---
|
||||||
void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos
|
void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos
|
||||||
void setMusicVolume(float volume) const; // Ajustar volumen de música
|
void setMusicVolume(float volume) const; // Ajustar volumen de música
|
||||||
|
|
||||||
// --- Configuración general ---
|
// --- Configuración general ---
|
||||||
void enable(bool value); // Establecer estado general
|
void enable(bool value); // Establecer estado general
|
||||||
void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general
|
void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general
|
||||||
void applySettings(); // Aplica la configuración
|
void applySettings(); // Aplica la configuración
|
||||||
|
|
||||||
// --- Configuración de sonidos ---
|
// --- Configuración de sonidos ---
|
||||||
void enableSound() { sound_enabled_ = true; } // Habilitar sonidos
|
void enableSound() { sound_enabled_ = true; } // Habilitar sonidos
|
||||||
void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos
|
void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos
|
||||||
void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos
|
void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos
|
||||||
void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos
|
void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos
|
||||||
|
|
||||||
// --- Configuración de música ---
|
// --- Configuración de música ---
|
||||||
void enableMusic() { music_enabled_ = true; } // Habilitar música
|
void enableMusic() { music_enabled_ = true; } // Habilitar música
|
||||||
void disableMusic() { music_enabled_ = false; } // Deshabilitar música
|
void disableMusic() { music_enabled_ = false; } // Deshabilitar música
|
||||||
void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música
|
void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música
|
||||||
void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música
|
void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música
|
||||||
|
|
||||||
// --- Consultas de estado ---
|
// --- Consultas de estado ---
|
||||||
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
|
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
|
||||||
[[nodiscard]] auto isSoundEnabled() const -> bool { return sound_enabled_; }
|
[[nodiscard]] auto isSoundEnabled() const -> bool { return sound_enabled_; }
|
||||||
[[nodiscard]] auto isMusicEnabled() const -> bool { return music_enabled_; }
|
[[nodiscard]] auto isMusicEnabled() const -> bool { return music_enabled_; }
|
||||||
[[nodiscard]] auto getMusicState() const -> MusicState { return music_.state; }
|
[[nodiscard]] auto getMusicState() const -> MusicState { return music_.state; }
|
||||||
[[nodiscard]] static auto getRealMusicState() -> MusicState;
|
[[nodiscard]] static auto getRealMusicState() -> MusicState;
|
||||||
[[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; }
|
[[nodiscard]] auto getCurrentMusicName() const -> const std::string& { return music_.name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Tipos anidados ---
|
// --- Tipos anidados ---
|
||||||
struct Music {
|
struct Music {
|
||||||
MusicState state{MusicState::STOPPED}; // Estado actual de la música
|
MusicState state{MusicState::STOPPED}; // Estado actual de la música
|
||||||
std::string name; // Última pista de música reproducida
|
std::string name; // Última pista de música reproducida
|
||||||
bool loop{false}; // Indica si se reproduce en bucle
|
bool loop{false}; // Indica si se reproduce en bucle
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
Audio(); // Constructor privado
|
Audio(); // Constructor privado
|
||||||
~Audio(); // Destructor privado
|
~Audio(); // Destructor privado
|
||||||
void initSDLAudio(); // Inicializa SDL Audio
|
void initSDLAudio(); // Inicializa SDL Audio
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
static Audio* instance; // Instancia única de Audio
|
static Audio* instance; // Instancia única de Audio
|
||||||
|
|
||||||
Music music_; // Estado de la música
|
Music music_; // Estado de la música
|
||||||
bool enabled_{true}; // Estado general del audio
|
bool enabled_{true}; // Estado general del audio
|
||||||
bool sound_enabled_{true}; // Estado de los efectos de sonido
|
bool sound_enabled_{true}; // Estado de los efectos de sonido
|
||||||
bool music_enabled_{true}; // Estado de la música
|
bool music_enabled_{true}; // Estado de la música
|
||||||
};
|
};
|
||||||
@@ -27,30 +27,30 @@ enum JA_Music_state { JA_MUSIC_INVALID,
|
|||||||
#define JA_MAX_GROUPS 2
|
#define JA_MAX_GROUPS 2
|
||||||
|
|
||||||
struct JA_Sound_t {
|
struct JA_Sound_t {
|
||||||
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
|
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
|
||||||
Uint32 length{0};
|
Uint32 length{0};
|
||||||
Uint8* buffer{NULL};
|
Uint8* buffer{NULL};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JA_Channel_t {
|
struct JA_Channel_t {
|
||||||
JA_Sound_t* sound{nullptr};
|
JA_Sound_t* sound{nullptr};
|
||||||
int pos{0};
|
int pos{0};
|
||||||
int times{0};
|
int times{0};
|
||||||
int group{0};
|
int group{0};
|
||||||
SDL_AudioStream* stream{nullptr};
|
SDL_AudioStream* stream{nullptr};
|
||||||
JA_Channel_state state{JA_CHANNEL_FREE};
|
JA_Channel_state state{JA_CHANNEL_FREE};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JA_Music_t {
|
struct JA_Music_t {
|
||||||
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
|
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
|
||||||
Uint32 length{0};
|
Uint32 length{0};
|
||||||
Uint8* buffer{nullptr};
|
Uint8* buffer{nullptr};
|
||||||
char* filename{nullptr};
|
char* filename{nullptr};
|
||||||
|
|
||||||
int pos{0};
|
int pos{0};
|
||||||
int times{0};
|
int times{0};
|
||||||
SDL_AudioStream* stream{nullptr};
|
SDL_AudioStream* stream{nullptr};
|
||||||
JA_Music_state state{JA_MUSIC_INVALID};
|
JA_Music_state state{JA_MUSIC_INVALID};
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Internal Global State ---
|
// --- Internal Global State ---
|
||||||
|
|||||||
@@ -18,117 +18,117 @@
|
|||||||
|
|
||||||
namespace GlobalInputs {
|
namespace GlobalInputs {
|
||||||
|
|
||||||
// Funciones internas
|
// Funciones internas
|
||||||
namespace {
|
namespace {
|
||||||
void handleQuit() {
|
void handleQuit() {
|
||||||
// En la escena GAME el comportamiento es siempre el mismo (con o sin modo kiosko)
|
// En la escena GAME el comportamiento es siempre el mismo (con o sin modo kiosko)
|
||||||
if (SceneManager::current == SceneManager::Scene::GAME) {
|
if (SceneManager::current == SceneManager::Scene::GAME) {
|
||||||
const std::string CODE = "PRESS AGAIN TO RETURN TO MENU";
|
const std::string CODE = "PRESS AGAIN TO RETURN TO MENU";
|
||||||
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
||||||
SceneManager::current = SceneManager::Scene::TITLE;
|
SceneManager::current = SceneManager::Scene::TITLE;
|
||||||
} else {
|
} else {
|
||||||
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// En modo kiosko, fuera de GAME: mostrar el texto del kiosko y no salir nunca
|
||||||
|
if (Options::kiosk.enabled) {
|
||||||
|
const std::string KIOSK_CODE = "KIOSK_EXIT";
|
||||||
|
if (!stringInVector(Notifier::get()->getCodes(), KIOSK_CODE)) {
|
||||||
|
Notifier::get()->show({Options::kiosk.text}, Notifier::Style::DEFAULT, -1, true, KIOSK_CODE);
|
||||||
|
}
|
||||||
|
// Segunda pulsación: notificación ya activa → no hacer nada
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comportamiento normal fuera del modo kiosko
|
||||||
|
const std::string CODE = "PRESS AGAIN TO EXIT";
|
||||||
|
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
||||||
|
SceneManager::current = SceneManager::Scene::QUIT;
|
||||||
|
} else {
|
||||||
|
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// En modo kiosko, fuera de GAME: mostrar el texto del kiosko y no salir nunca
|
void handleSkipSection() {
|
||||||
if (Options::kiosk.enabled) {
|
switch (SceneManager::current) {
|
||||||
const std::string KIOSK_CODE = "KIOSK_EXIT";
|
case SceneManager::Scene::LOGO:
|
||||||
if (!stringInVector(Notifier::get()->getCodes(), KIOSK_CODE)) {
|
case SceneManager::Scene::LOADING_SCREEN:
|
||||||
Notifier::get()->show({Options::kiosk.text}, Notifier::Style::DEFAULT, -1, true, KIOSK_CODE);
|
case SceneManager::Scene::CREDITS:
|
||||||
|
case SceneManager::Scene::DEMO:
|
||||||
|
case SceneManager::Scene::GAME_OVER:
|
||||||
|
case SceneManager::Scene::ENDING:
|
||||||
|
case SceneManager::Scene::ENDING2:
|
||||||
|
SceneManager::current = SceneManager::Scene::TITLE;
|
||||||
|
SceneManager::options = SceneManager::Options::NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Segunda pulsación: notificación ya activa → no hacer nada
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comportamiento normal fuera del modo kiosko
|
void handleToggleBorder() {
|
||||||
const std::string CODE = "PRESS AGAIN TO EXIT";
|
Screen::get()->toggleBorder();
|
||||||
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
Notifier::get()->show({"BORDER " + std::string(Options::video.border.enabled ? "ENABLED" : "DISABLED")});
|
||||||
SceneManager::current = SceneManager::Scene::QUIT;
|
}
|
||||||
} else {
|
|
||||||
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleSkipSection() {
|
void handleToggleVideoMode() {
|
||||||
switch (SceneManager::current) {
|
Screen::get()->toggleVideoMode();
|
||||||
case SceneManager::Scene::LOGO:
|
Notifier::get()->show({"FULLSCREEN " + std::string(static_cast<int>(Options::video.fullscreen) == 0 ? "DISABLED" : "ENABLED")});
|
||||||
case SceneManager::Scene::LOADING_SCREEN:
|
}
|
||||||
case SceneManager::Scene::CREDITS:
|
|
||||||
case SceneManager::Scene::DEMO:
|
|
||||||
case SceneManager::Scene::GAME_OVER:
|
|
||||||
case SceneManager::Scene::ENDING:
|
|
||||||
case SceneManager::Scene::ENDING2:
|
|
||||||
SceneManager::current = SceneManager::Scene::TITLE;
|
|
||||||
SceneManager::options = SceneManager::Options::NONE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
void handleDecWindowZoom() {
|
||||||
break;
|
if (Screen::get()->decWindowZoom()) {
|
||||||
}
|
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleToggleBorder() {
|
void handleIncWindowZoom() {
|
||||||
Screen::get()->toggleBorder();
|
if (Screen::get()->incWindowZoom()) {
|
||||||
Notifier::get()->show({"BORDER " + std::string(Options::video.border.enabled ? "ENABLED" : "DISABLED")});
|
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleToggleVideoMode() {
|
void handleTogglePostFX() {
|
||||||
Screen::get()->toggleVideoMode();
|
Screen::get()->togglePostFX();
|
||||||
Notifier::get()->show({"FULLSCREEN " + std::string(static_cast<int>(Options::video.fullscreen) == 0 ? "DISABLED" : "ENABLED")});
|
Notifier::get()->show({"POSTFX " + std::string(Options::video.postfx ? "ENABLED" : "DISABLED")});
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleDecWindowZoom() {
|
void handleNextPostFXPreset() {
|
||||||
if (Screen::get()->decWindowZoom()) {
|
if (!Options::postfx_presets.empty()) {
|
||||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
|
||||||
}
|
Screen::get()->reloadPostFX();
|
||||||
}
|
Notifier::get()->show({"POSTFX " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void handleIncWindowZoom() {
|
void handleNextPalette() {
|
||||||
if (Screen::get()->incWindowZoom()) {
|
Screen::get()->nextPalette();
|
||||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void handleTogglePostFX() {
|
void handlePreviousPalette() {
|
||||||
Screen::get()->togglePostFX();
|
Screen::get()->previousPalette();
|
||||||
Notifier::get()->show({"POSTFX " + std::string(Options::video.postfx ? "ENABLED" : "DISABLED")});
|
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNextPostFXPreset() {
|
void handleToggleIntegerScale() {
|
||||||
if (!Options::postfx_presets.empty()) {
|
Screen::get()->toggleIntegerScale();
|
||||||
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
|
Screen::get()->setVideoMode(Options::video.fullscreen);
|
||||||
Screen::get()->reloadPostFX();
|
Notifier::get()->show({"INTEGER SCALE " + std::string(Options::video.integer_scale ? "ENABLED" : "DISABLED")});
|
||||||
Notifier::get()->show({"POSTFX " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name});
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleNextPalette() {
|
void handleToggleVSync() {
|
||||||
Screen::get()->nextPalette();
|
Screen::get()->toggleVSync();
|
||||||
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
Notifier::get()->show({"V-SYNC " + std::string(Options::video.vertical_sync ? "ENABLED" : "DISABLED")});
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlePreviousPalette() {
|
|
||||||
Screen::get()->previousPalette();
|
|
||||||
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleToggleIntegerScale() {
|
|
||||||
Screen::get()->toggleIntegerScale();
|
|
||||||
Screen::get()->setVideoMode(Options::video.fullscreen);
|
|
||||||
Notifier::get()->show({"INTEGER SCALE " + std::string(Options::video.integer_scale ? "ENABLED" : "DISABLED")});
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleToggleVSync() {
|
|
||||||
Screen::get()->toggleVSync();
|
|
||||||
Notifier::get()->show({"V-SYNC " + std::string(Options::video.vertical_sync ? "ENABLED" : "DISABLED")});
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void handleShowDebugInfo() {
|
void handleShowDebugInfo() {
|
||||||
Screen::get()->toggleDebugInfo();
|
Screen::get()->toggleDebugInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void handleToggleDebug() {
|
void handleToggleDebug() {
|
||||||
@@ -138,138 +138,138 @@ void handleToggleDebug() {
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Detecta qué acción global ha sido presionada (si alguna)
|
// Detecta qué acción global ha sido presionada (si alguna)
|
||||||
auto getPressedAction() -> InputAction {
|
auto getPressedAction() -> InputAction {
|
||||||
if (Input::get()->checkAction(InputAction::EXIT, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::EXIT, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::EXIT;
|
return InputAction::EXIT;
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::ACCEPT, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::ACCEPT;
|
return InputAction::ACCEPT;
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_BORDER, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::TOGGLE_BORDER, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::TOGGLE_BORDER;
|
return InputAction::TOGGLE_BORDER;
|
||||||
}
|
}
|
||||||
if (!Options::kiosk.enabled) {
|
if (!Options::kiosk.enabled) {
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_FULLSCREEN, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::TOGGLE_FULLSCREEN, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::TOGGLE_FULLSCREEN;
|
return InputAction::TOGGLE_FULLSCREEN;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::WINDOW_DEC_ZOOM, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::WINDOW_DEC_ZOOM;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::WINDOW_INC_ZOOM, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::WINDOW_INC_ZOOM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::TOGGLE_POSTFX, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
|
||||||
|
return InputAction::NEXT_POSTFX_PRESET;
|
||||||
|
}
|
||||||
|
return InputAction::TOGGLE_POSTFX;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::NEXT_PALETTE;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::PREVIOUS_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::PREVIOUS_PALETTE;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::TOGGLE_INTEGER_SCALE, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::TOGGLE_INTEGER_SCALE;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::TOGGLE_VSYNC, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::TOGGLE_VSYNC;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::TOGGLE_DEBUG, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::TOGGLE_DEBUG;
|
||||||
|
}
|
||||||
|
if (Input::get()->checkAction(InputAction::SHOW_DEBUG_INFO, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
|
return InputAction::SHOW_DEBUG_INFO;
|
||||||
|
}
|
||||||
|
return InputAction::NONE;
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::WINDOW_DEC_ZOOM, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::WINDOW_DEC_ZOOM;
|
} // namespace
|
||||||
|
|
||||||
|
// Funciones públicas
|
||||||
|
|
||||||
|
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||||
|
void handle() {
|
||||||
|
// Salida de administrador en modo kiosko (Ctrl+Shift+Alt+Q)
|
||||||
|
if (Options::kiosk.enabled) {
|
||||||
|
SDL_Keymod mod = SDL_GetModState();
|
||||||
|
const bool* ks = SDL_GetKeyboardState(nullptr);
|
||||||
|
if (((mod & SDL_KMOD_CTRL) != 0U) && ((mod & SDL_KMOD_SHIFT) != 0U) && ((mod & SDL_KMOD_ALT) != 0U) && ks[SDL_SCANCODE_Q]) {
|
||||||
|
SceneManager::current = SceneManager::Scene::QUIT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::WINDOW_INC_ZOOM, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::WINDOW_INC_ZOOM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_POSTFX, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
|
|
||||||
return InputAction::NEXT_POSTFX_PRESET;
|
|
||||||
}
|
|
||||||
return InputAction::TOGGLE_POSTFX;
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::NEXT_PALETTE;
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::PREVIOUS_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::PREVIOUS_PALETTE;
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_INTEGER_SCALE, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::TOGGLE_INTEGER_SCALE;
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_VSYNC, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::TOGGLE_VSYNC;
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_DEBUG, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::TOGGLE_DEBUG;
|
|
||||||
}
|
|
||||||
if (Input::get()->checkAction(InputAction::SHOW_DEBUG_INFO, Input::DO_NOT_ALLOW_REPEAT)) {
|
|
||||||
return InputAction::SHOW_DEBUG_INFO;
|
|
||||||
}
|
|
||||||
return InputAction::NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
// Detectar qué acción global está siendo presionada
|
||||||
|
InputAction action = getPressedAction();
|
||||||
|
|
||||||
// Funciones públicas
|
// Ejecutar el handler correspondiente usando switch statement
|
||||||
|
switch (action) {
|
||||||
|
case InputAction::EXIT:
|
||||||
|
handleQuit();
|
||||||
|
break;
|
||||||
|
|
||||||
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
case InputAction::ACCEPT:
|
||||||
void handle() {
|
handleSkipSection();
|
||||||
// Salida de administrador en modo kiosko (Ctrl+Shift+Alt+Q)
|
break;
|
||||||
if (Options::kiosk.enabled) {
|
|
||||||
SDL_Keymod mod = SDL_GetModState();
|
|
||||||
const bool* ks = SDL_GetKeyboardState(nullptr);
|
|
||||||
if (((mod & SDL_KMOD_CTRL) != 0U) && ((mod & SDL_KMOD_SHIFT) != 0U) && ((mod & SDL_KMOD_ALT) != 0U) && ks[SDL_SCANCODE_Q]) {
|
|
||||||
SceneManager::current = SceneManager::Scene::QUIT;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detectar qué acción global está siendo presionada
|
case InputAction::TOGGLE_BORDER:
|
||||||
InputAction action = getPressedAction();
|
handleToggleBorder();
|
||||||
|
break;
|
||||||
|
|
||||||
// Ejecutar el handler correspondiente usando switch statement
|
case InputAction::TOGGLE_FULLSCREEN:
|
||||||
switch (action) {
|
handleToggleVideoMode();
|
||||||
case InputAction::EXIT:
|
break;
|
||||||
handleQuit();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case InputAction::ACCEPT:
|
case InputAction::WINDOW_DEC_ZOOM:
|
||||||
handleSkipSection();
|
handleDecWindowZoom();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::TOGGLE_BORDER:
|
case InputAction::WINDOW_INC_ZOOM:
|
||||||
handleToggleBorder();
|
handleIncWindowZoom();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::TOGGLE_FULLSCREEN:
|
case InputAction::TOGGLE_POSTFX:
|
||||||
handleToggleVideoMode();
|
handleTogglePostFX();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::WINDOW_DEC_ZOOM:
|
case InputAction::NEXT_POSTFX_PRESET:
|
||||||
handleDecWindowZoom();
|
handleNextPostFXPreset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::WINDOW_INC_ZOOM:
|
case InputAction::NEXT_PALETTE:
|
||||||
handleIncWindowZoom();
|
handleNextPalette();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::TOGGLE_POSTFX:
|
case InputAction::PREVIOUS_PALETTE:
|
||||||
handleTogglePostFX();
|
handlePreviousPalette();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::NEXT_POSTFX_PRESET:
|
case InputAction::TOGGLE_INTEGER_SCALE:
|
||||||
handleNextPostFXPreset();
|
handleToggleIntegerScale();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::NEXT_PALETTE:
|
case InputAction::TOGGLE_VSYNC:
|
||||||
handleNextPalette();
|
handleToggleVSync();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::PREVIOUS_PALETTE:
|
case InputAction::TOGGLE_DEBUG:
|
||||||
handlePreviousPalette();
|
// handleToggleDebug();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InputAction::TOGGLE_INTEGER_SCALE:
|
|
||||||
handleToggleIntegerScale();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case InputAction::TOGGLE_VSYNC:
|
|
||||||
handleToggleVSync();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case InputAction::TOGGLE_DEBUG:
|
|
||||||
// handleToggleDebug();
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
case InputAction::SHOW_DEBUG_INFO:
|
case InputAction::SHOW_DEBUG_INFO:
|
||||||
handleShowDebugInfo();
|
handleShowDebugInfo();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case InputAction::NONE:
|
case InputAction::NONE:
|
||||||
default:
|
default:
|
||||||
// No se presionó ninguna acción global
|
// No se presionó ninguna acción global
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // namespace GlobalInputs
|
} // namespace GlobalInputs
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace GlobalInputs {
|
namespace GlobalInputs {
|
||||||
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||||
void handle();
|
void handle();
|
||||||
} // namespace GlobalInputs
|
} // namespace GlobalInputs
|
||||||
@@ -13,128 +13,128 @@
|
|||||||
|
|
||||||
// --- Clase Input: gestiona la entrada de teclado y mandos (singleton) ---
|
// --- Clase Input: gestiona la entrada de teclado y mandos (singleton) ---
|
||||||
class Input {
|
class Input {
|
||||||
public:
|
public:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr bool ALLOW_REPEAT = true; // Permite repetición
|
static constexpr bool ALLOW_REPEAT = true; // Permite repetición
|
||||||
static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición
|
static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición
|
||||||
static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado
|
static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado
|
||||||
static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado
|
static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado
|
||||||
static constexpr int TRIGGER_L2_AS_BUTTON = 100; // L2 como botón
|
static constexpr int TRIGGER_L2_AS_BUTTON = 100; // L2 como botón
|
||||||
static constexpr int TRIGGER_R2_AS_BUTTON = 101; // R2 como botón
|
static constexpr int TRIGGER_R2_AS_BUTTON = 101; // R2 como botón
|
||||||
|
|
||||||
// --- Tipos ---
|
// --- Tipos ---
|
||||||
using Action = InputAction; // Alias para mantener compatibilidad
|
using Action = InputAction; // Alias para mantener compatibilidad
|
||||||
|
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
struct KeyState {
|
struct KeyState {
|
||||||
Uint8 scancode{0}; // Scancode asociado
|
Uint8 scancode{0}; // Scancode asociado
|
||||||
bool is_held{false}; // Está pulsada ahora mismo
|
bool is_held{false}; // Está pulsada ahora mismo
|
||||||
bool just_pressed{false}; // Se acaba de pulsar en este fotograma
|
bool just_pressed{false}; // Se acaba de pulsar en este fotograma
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ButtonState {
|
struct ButtonState {
|
||||||
int button{static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID)}; // GameControllerButton asociado
|
int button{static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID)}; // GameControllerButton asociado
|
||||||
bool is_held{false}; // Está pulsada ahora mismo
|
bool is_held{false}; // Está pulsada ahora mismo
|
||||||
bool just_pressed{false}; // Se acaba de pulsar en este fotograma
|
bool just_pressed{false}; // Se acaba de pulsar en este fotograma
|
||||||
bool axis_active{false}; // Estado del eje
|
bool axis_active{false}; // Estado del eje
|
||||||
bool trigger_active{false}; // Estado del trigger como botón digital
|
bool trigger_active{false}; // Estado del trigger como botón digital
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Keyboard {
|
struct Keyboard {
|
||||||
std::unordered_map<Action, KeyState> bindings; // Mapa de acciones a estados de tecla
|
std::unordered_map<Action, KeyState> bindings; // Mapa de acciones a estados de tecla
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Gamepad {
|
struct Gamepad {
|
||||||
SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL
|
SDL_Gamepad* pad{nullptr}; // Puntero al gamepad SDL
|
||||||
SDL_JoystickID instance_id{0}; // ID de instancia del joystick
|
SDL_JoystickID instance_id{0}; // ID de instancia del joystick
|
||||||
std::string name; // Nombre del gamepad
|
std::string name; // Nombre del gamepad
|
||||||
std::string path; // Ruta del dispositivo
|
std::string path; // Ruta del dispositivo
|
||||||
std::unordered_map<Action, ButtonState> bindings; // Mapa de acciones a estados de botón
|
std::unordered_map<Action, ButtonState> bindings; // Mapa de acciones a estados de botón
|
||||||
|
|
||||||
explicit Gamepad(SDL_Gamepad* gamepad)
|
explicit Gamepad(SDL_Gamepad* gamepad)
|
||||||
: pad(gamepad),
|
: pad(gamepad),
|
||||||
instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))),
|
instance_id(SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad))),
|
||||||
name(std::string(SDL_GetGamepadName(gamepad))),
|
name(std::string(SDL_GetGamepadName(gamepad))),
|
||||||
path(std::string(SDL_GetGamepadPath(pad))),
|
path(std::string(SDL_GetGamepadPath(pad))),
|
||||||
bindings{
|
bindings{
|
||||||
// Movimiento del jugador
|
// Movimiento del jugador
|
||||||
{Action::LEFT, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}},
|
{Action::LEFT, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT)}},
|
||||||
{Action::RIGHT, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}},
|
{Action::RIGHT, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)}},
|
||||||
{Action::JUMP, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_WEST)}}} {}
|
{Action::JUMP, ButtonState{.button = static_cast<int>(SDL_GAMEPAD_BUTTON_WEST)}}} {}
|
||||||
|
|
||||||
~Gamepad() {
|
~Gamepad() {
|
||||||
if (pad != nullptr) {
|
if (pad != nullptr) {
|
||||||
SDL_CloseGamepad(pad);
|
SDL_CloseGamepad(pad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reasigna un botón a una acción
|
// Reasigna un botón a una acción
|
||||||
void rebindAction(Action action, SDL_GamepadButton new_button) {
|
void rebindAction(Action action, SDL_GamepadButton new_button) {
|
||||||
bindings[action].button = static_cast<int>(new_button);
|
bindings[action].button = static_cast<int>(new_button);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Tipos ---
|
// --- Tipos ---
|
||||||
using Gamepads = std::vector<std::shared_ptr<Gamepad>>; // Vector de gamepads
|
using Gamepads = std::vector<std::shared_ptr<Gamepad>>; // Vector de gamepads
|
||||||
|
|
||||||
// --- Singleton ---
|
// --- Singleton ---
|
||||||
static void init(const std::string& game_controller_db_path);
|
static void init(const std::string& game_controller_db_path);
|
||||||
static void destroy();
|
static void destroy();
|
||||||
static auto get() -> Input*;
|
static auto get() -> Input*;
|
||||||
|
|
||||||
// --- Actualización del sistema ---
|
// --- Actualización del sistema ---
|
||||||
void update(); // Actualiza estados de entrada
|
void update(); // Actualiza estados de entrada
|
||||||
|
|
||||||
// --- Configuración de controles ---
|
// --- Configuración de controles ---
|
||||||
void bindKey(Action action, SDL_Scancode code);
|
void bindKey(Action action, SDL_Scancode code);
|
||||||
void applyKeyboardBindingsFromOptions();
|
void applyKeyboardBindingsFromOptions();
|
||||||
void applyGamepadBindingsFromOptions();
|
void applyGamepadBindingsFromOptions();
|
||||||
static void bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action, SDL_GamepadButton button);
|
static void bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action, SDL_GamepadButton button);
|
||||||
static void bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action_target, Action action_source);
|
static void bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action_target, Action action_source);
|
||||||
|
|
||||||
// --- Consulta de entrada ---
|
// --- Consulta de entrada ---
|
||||||
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr<Gamepad>& gamepad = nullptr) -> bool;
|
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr<Gamepad>& gamepad = nullptr) -> bool;
|
||||||
auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr<Gamepad>& gamepad = nullptr) -> bool;
|
auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr<Gamepad>& gamepad = nullptr) -> bool;
|
||||||
auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool;
|
auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool;
|
||||||
void resetInputStates();
|
void resetInputStates();
|
||||||
|
|
||||||
// --- Gestión de gamepads ---
|
// --- Gestión de gamepads ---
|
||||||
[[nodiscard]] auto gameControllerFound() const -> bool;
|
[[nodiscard]] auto gameControllerFound() const -> bool;
|
||||||
[[nodiscard]] auto getNumGamepads() const -> int;
|
[[nodiscard]] auto getNumGamepads() const -> int;
|
||||||
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
|
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
|
||||||
auto getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad>;
|
auto getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad>;
|
||||||
auto getGamepads() const -> const Gamepads& { return gamepads_; }
|
auto getGamepads() const -> const Gamepads& { return gamepads_; }
|
||||||
auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr<Gamepad>;
|
auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr<Gamepad>;
|
||||||
static auto getControllerName(const std::shared_ptr<Gamepad>& gamepad) -> std::string;
|
static auto getControllerName(const std::shared_ptr<Gamepad>& gamepad) -> std::string;
|
||||||
auto getControllerNames() const -> std::vector<std::string>;
|
auto getControllerNames() const -> std::vector<std::string>;
|
||||||
[[nodiscard]] static auto getControllerBinding(const std::shared_ptr<Gamepad>& gamepad, Action action) -> SDL_GamepadButton;
|
[[nodiscard]] static auto getControllerBinding(const std::shared_ptr<Gamepad>& gamepad, Action action) -> SDL_GamepadButton;
|
||||||
void printConnectedGamepads() const;
|
void printConnectedGamepads() const;
|
||||||
|
|
||||||
// --- Eventos ---
|
// --- Eventos ---
|
||||||
auto handleEvent(const SDL_Event& event) -> std::string;
|
auto handleEvent(const SDL_Event& event) -> std::string;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr Sint16 AXIS_THRESHOLD = 30000; // Umbral para ejes analógicos
|
static constexpr Sint16 AXIS_THRESHOLD = 30000; // Umbral para ejes analógicos
|
||||||
static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (50% del rango)
|
static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (50% del rango)
|
||||||
static constexpr std::array<Action, 1> BUTTON_INPUTS = {Action::JUMP}; // Inputs que usan botones
|
static constexpr std::array<Action, 1> BUTTON_INPUTS = {Action::JUMP}; // Inputs que usan botones
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
explicit Input(std::string game_controller_db_path);
|
explicit Input(std::string game_controller_db_path);
|
||||||
~Input() = default;
|
~Input() = default;
|
||||||
|
|
||||||
void initSDLGamePad();
|
void initSDLGamePad();
|
||||||
static auto checkAxisInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool;
|
static auto checkAxisInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool;
|
||||||
static auto checkTriggerInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool;
|
static auto checkTriggerInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool;
|
||||||
auto addGamepad(int device_index) -> std::string;
|
auto addGamepad(int device_index) -> std::string;
|
||||||
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
||||||
void addGamepadMappingsFromFile();
|
void addGamepadMappingsFromFile();
|
||||||
void discoverGamepads();
|
void discoverGamepads();
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
static Input* instance; // Instancia única del singleton
|
static Input* instance; // Instancia única del singleton
|
||||||
|
|
||||||
Gamepads gamepads_; // Lista de gamepads conectados
|
Gamepads gamepads_; // Lista de gamepads conectados
|
||||||
Keyboard keyboard_{}; // Estado del teclado
|
Keyboard keyboard_{}; // Estado del teclado
|
||||||
std::string gamepad_mappings_file_; // Ruta al archivo de mappings
|
std::string gamepad_mappings_file_; // Ruta al archivo de mappings
|
||||||
};
|
};
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
#include "core/input/mouse.hpp"
|
#include "core/input/mouse.hpp"
|
||||||
|
|
||||||
namespace Mouse {
|
namespace Mouse {
|
||||||
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
|
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
|
||||||
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
|
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
|
||||||
bool cursor_visible = true; // Estado del cursor
|
bool cursor_visible = true; // Estado del cursor
|
||||||
|
|
||||||
void handleEvent(const SDL_Event& event) {
|
void handleEvent(const SDL_Event& event) {
|
||||||
if (event.type == SDL_EVENT_MOUSE_MOTION) {
|
if (event.type == SDL_EVENT_MOUSE_MOTION) {
|
||||||
last_mouse_move_time = SDL_GetTicks();
|
last_mouse_move_time = SDL_GetTicks();
|
||||||
if (!cursor_visible) {
|
if (!cursor_visible) {
|
||||||
SDL_ShowCursor();
|
SDL_ShowCursor();
|
||||||
cursor_visible = true;
|
cursor_visible = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void updateCursorVisibility() {
|
void updateCursorVisibility() {
|
||||||
Uint32 current_time = SDL_GetTicks();
|
Uint32 current_time = SDL_GetTicks();
|
||||||
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
|
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
|
||||||
SDL_HideCursor();
|
SDL_HideCursor();
|
||||||
cursor_visible = false;
|
cursor_visible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // namespace Mouse
|
} // namespace Mouse
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
namespace Mouse {
|
namespace Mouse {
|
||||||
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor
|
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor
|
||||||
extern Uint32 last_mouse_move_time; // Última vez que el ratón se movió
|
extern Uint32 last_mouse_move_time; // Última vez que el ratón se movió
|
||||||
extern bool cursor_visible; // Estado del cursor
|
extern bool cursor_visible; // Estado del cursor
|
||||||
|
|
||||||
void handleEvent(const SDL_Event& event);
|
void handleEvent(const SDL_Event& event);
|
||||||
void updateCursorVisibility();
|
void updateCursorVisibility();
|
||||||
} // namespace Mouse
|
} // namespace Mouse
|
||||||
@@ -7,289 +7,289 @@
|
|||||||
|
|
||||||
namespace GIF {
|
namespace GIF {
|
||||||
|
|
||||||
// Función inline para reemplazar el macro READ.
|
// Función inline para reemplazar el macro READ.
|
||||||
// Actualiza el puntero 'buffer' tras copiar 'size' bytes a 'dst'.
|
// Actualiza el puntero 'buffer' tras copiar 'size' bytes a 'dst'.
|
||||||
inline void readBytes(const uint8_t*& buffer, void* dst, size_t size) {
|
inline void readBytes(const uint8_t*& buffer, void* dst, size_t size) {
|
||||||
std::memcpy(dst, buffer, size);
|
std::memcpy(dst, buffer, size);
|
||||||
buffer += size;
|
buffer += size;
|
||||||
}
|
|
||||||
|
|
||||||
// Inicializa el diccionario LZW con los valores iniciales
|
|
||||||
inline void initializeDictionary(std::vector<DictionaryEntry>& dictionary, int code_length, int& dictionary_ind) {
|
|
||||||
int size = 1 << code_length;
|
|
||||||
dictionary.resize(1 << (code_length + 1));
|
|
||||||
for (dictionary_ind = 0; dictionary_ind < size; dictionary_ind++) {
|
|
||||||
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
|
||||||
dictionary[dictionary_ind].prev = -1;
|
|
||||||
dictionary[dictionary_ind].len = 1;
|
|
||||||
}
|
|
||||||
dictionary_ind += 2; // Reservamos espacio para clear y stop codes
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lee los próximos bits del stream de entrada para formar un código
|
|
||||||
inline auto readNextCode(const uint8_t*& input, int& input_length, unsigned int& mask, int code_length) -> int {
|
|
||||||
int code = 0;
|
|
||||||
for (int i = 0; i < (code_length + 1); i++) {
|
|
||||||
if (input_length <= 0) {
|
|
||||||
throw std::runtime_error("Unexpected end of input in decompress");
|
|
||||||
}
|
|
||||||
int bit = ((*input & mask) != 0) ? 1 : 0;
|
|
||||||
mask <<= 1;
|
|
||||||
if (mask == 0x100) {
|
|
||||||
mask = 0x01;
|
|
||||||
input++;
|
|
||||||
input_length--;
|
|
||||||
}
|
|
||||||
code |= (bit << i);
|
|
||||||
}
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encuentra el primer byte de una cadena del diccionario
|
|
||||||
inline auto findFirstByte(const std::vector<DictionaryEntry>& dictionary, int code) -> uint8_t {
|
|
||||||
int ptr = code;
|
|
||||||
while (dictionary[ptr].prev != -1) {
|
|
||||||
ptr = dictionary[ptr].prev;
|
|
||||||
}
|
|
||||||
return dictionary[ptr].byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Agrega una nueva entrada al diccionario
|
|
||||||
inline void addDictionaryEntry(std::vector<DictionaryEntry>& dictionary, int& dictionary_ind, int& code_length, int prev, int code) {
|
|
||||||
uint8_t first_byte;
|
|
||||||
if (code == dictionary_ind) {
|
|
||||||
first_byte = findFirstByte(dictionary, prev);
|
|
||||||
} else {
|
|
||||||
first_byte = findFirstByte(dictionary, code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dictionary[dictionary_ind].byte = first_byte;
|
// Inicializa el diccionario LZW con los valores iniciales
|
||||||
dictionary[dictionary_ind].prev = prev;
|
inline void initializeDictionary(std::vector<DictionaryEntry>& dictionary, int code_length, int& dictionary_ind) {
|
||||||
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
|
int size = 1 << code_length;
|
||||||
dictionary_ind++;
|
|
||||||
|
|
||||||
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
|
|
||||||
code_length++;
|
|
||||||
dictionary.resize(1 << (code_length + 1));
|
dictionary.resize(1 << (code_length + 1));
|
||||||
}
|
for (dictionary_ind = 0; dictionary_ind < size; dictionary_ind++) {
|
||||||
}
|
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
||||||
|
dictionary[dictionary_ind].prev = -1;
|
||||||
// Escribe la cadena decodificada al buffer de salida
|
dictionary[dictionary_ind].len = 1;
|
||||||
inline auto writeDecodedString(const std::vector<DictionaryEntry>& dictionary, int code, uint8_t*& out) -> int {
|
|
||||||
int cur_code = code;
|
|
||||||
int match_len = dictionary[cur_code].len;
|
|
||||||
while (cur_code != -1) {
|
|
||||||
out[dictionary[cur_code].len - 1] = dictionary[cur_code].byte;
|
|
||||||
if (dictionary[cur_code].prev == cur_code) {
|
|
||||||
std::cerr << "Internal error; self-reference detected." << '\n';
|
|
||||||
throw std::runtime_error("Internal error in decompress: self-reference");
|
|
||||||
}
|
}
|
||||||
cur_code = dictionary[cur_code].prev;
|
dictionary_ind += 2; // Reservamos espacio para clear y stop codes
|
||||||
}
|
|
||||||
out += match_len;
|
|
||||||
return match_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gif::decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out) {
|
|
||||||
// Verifica que el code_length tenga un rango razonable.
|
|
||||||
if (code_length < 2 || code_length > 12) {
|
|
||||||
throw std::runtime_error("Invalid LZW code length");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int prev = -1;
|
// Lee los próximos bits del stream de entrada para formar un código
|
||||||
std::vector<DictionaryEntry> dictionary;
|
inline auto readNextCode(const uint8_t*& input, int& input_length, unsigned int& mask, int code_length) -> int {
|
||||||
int dictionary_ind;
|
int code = 0;
|
||||||
unsigned int mask = 0x01;
|
for (int i = 0; i < (code_length + 1); i++) {
|
||||||
int reset_code_length = code_length;
|
if (input_length <= 0) {
|
||||||
int clear_code = 1 << code_length;
|
throw std::runtime_error("Unexpected end of input in decompress");
|
||||||
int stop_code = clear_code + 1;
|
|
||||||
|
|
||||||
// Inicializamos el diccionario con el tamaño correspondiente.
|
|
||||||
initializeDictionary(dictionary, code_length, dictionary_ind);
|
|
||||||
|
|
||||||
// Bucle principal: procesar el stream comprimido.
|
|
||||||
while (input_length > 0) {
|
|
||||||
int code = readNextCode(input, input_length, mask, code_length);
|
|
||||||
|
|
||||||
if (code == clear_code) {
|
|
||||||
// Reinicia el diccionario.
|
|
||||||
code_length = reset_code_length;
|
|
||||||
initializeDictionary(dictionary, code_length, dictionary_ind);
|
|
||||||
prev = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (code == stop_code) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prev > -1 && code_length < 12) {
|
|
||||||
if (code > dictionary_ind) {
|
|
||||||
std::cerr << "code = " << std::hex << code
|
|
||||||
<< ", but dictionary_ind = " << dictionary_ind << '\n';
|
|
||||||
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
|
||||||
}
|
}
|
||||||
|
int bit = ((*input & mask) != 0) ? 1 : 0;
|
||||||
addDictionaryEntry(dictionary, dictionary_ind, code_length, prev, code);
|
mask <<= 1;
|
||||||
}
|
if (mask == 0x100) {
|
||||||
|
mask = 0x01;
|
||||||
prev = code;
|
input++;
|
||||||
|
input_length--;
|
||||||
// Verifica que 'code' sea un índice válido antes de usarlo.
|
|
||||||
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
|
|
||||||
std::cerr << "Invalid LZW code " << code
|
|
||||||
<< ", dictionary size " << dictionary.size() << '\n';
|
|
||||||
throw std::runtime_error("LZW error: invalid code encountered");
|
|
||||||
}
|
|
||||||
|
|
||||||
writeDecodedString(dictionary, code, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> {
|
|
||||||
std::vector<uint8_t> data;
|
|
||||||
uint8_t block_size = *buffer;
|
|
||||||
buffer++;
|
|
||||||
while (block_size != 0) {
|
|
||||||
data.insert(data.end(), buffer, buffer + block_size);
|
|
||||||
buffer += block_size;
|
|
||||||
block_size = *buffer;
|
|
||||||
buffer++;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Gif::processImageDescriptor(const uint8_t*& buffer, const std::vector<RGB>& gct, int resolution_bits) -> std::vector<uint8_t> {
|
|
||||||
ImageDescriptor image_descriptor;
|
|
||||||
// Lee 9 bytes para el image descriptor.
|
|
||||||
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
|
|
||||||
|
|
||||||
uint8_t lzw_code_size;
|
|
||||||
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
|
|
||||||
|
|
||||||
std::vector<uint8_t> compressed_data = readSubBlocks(buffer);
|
|
||||||
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
|
|
||||||
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
|
|
||||||
|
|
||||||
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
|
|
||||||
return uncompressed_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Gif::loadPalette(const uint8_t* buffer) -> std::vector<uint32_t> {
|
|
||||||
uint8_t header[6];
|
|
||||||
std::memcpy(header, buffer, 6);
|
|
||||||
buffer += 6;
|
|
||||||
|
|
||||||
ScreenDescriptor screen_descriptor;
|
|
||||||
std::memcpy(&screen_descriptor, buffer, sizeof(ScreenDescriptor));
|
|
||||||
buffer += sizeof(ScreenDescriptor);
|
|
||||||
|
|
||||||
std::vector<uint32_t> global_color_table;
|
|
||||||
if ((screen_descriptor.fields & 0x80) != 0) {
|
|
||||||
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
|
||||||
global_color_table.resize(global_color_table_size);
|
|
||||||
for (int i = 0; i < global_color_table_size; ++i) {
|
|
||||||
uint8_t r = buffer[0];
|
|
||||||
uint8_t g = buffer[1];
|
|
||||||
uint8_t b = buffer[2];
|
|
||||||
global_color_table[i] = (r << 16) | (g << 8) | b;
|
|
||||||
buffer += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return global_color_table;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Gif::processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t> {
|
|
||||||
// Leer la cabecera de 6 bytes ("GIF87a" o "GIF89a")
|
|
||||||
uint8_t header[6];
|
|
||||||
std::memcpy(header, buffer, 6);
|
|
||||||
buffer += 6;
|
|
||||||
|
|
||||||
// Opcional: Validar header
|
|
||||||
std::string header_str(reinterpret_cast<char*>(header), 6);
|
|
||||||
if (header_str != "GIF87a" && header_str != "GIF89a") {
|
|
||||||
throw std::runtime_error("Formato de archivo GIF inválido.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leer el Screen Descriptor (7 bytes, empaquetado sin padding)
|
|
||||||
ScreenDescriptor screen_descriptor;
|
|
||||||
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
|
|
||||||
|
|
||||||
// Asigna ancho y alto
|
|
||||||
w = screen_descriptor.width;
|
|
||||||
h = screen_descriptor.height;
|
|
||||||
|
|
||||||
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
|
|
||||||
std::vector<RGB> global_color_table;
|
|
||||||
if ((screen_descriptor.fields & 0x80) != 0) {
|
|
||||||
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
|
||||||
global_color_table.resize(global_color_table_size);
|
|
||||||
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
|
|
||||||
buffer += 3 * global_color_table_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supongamos que 'buffer' es el puntero actual y TRAILER es 0x3B
|
|
||||||
uint8_t block_type = *buffer++;
|
|
||||||
while (block_type != TRAILER) {
|
|
||||||
if (block_type == EXTENSION_INTRODUCER) // 0x21
|
|
||||||
{
|
|
||||||
// Se lee la etiqueta de extensión, la cual indica el tipo de extensión.
|
|
||||||
uint8_t extension_label = *buffer++;
|
|
||||||
switch (extension_label) {
|
|
||||||
case GRAPHIC_CONTROL: // 0xF9
|
|
||||||
{
|
|
||||||
// Procesar Graphic Control Extension:
|
|
||||||
uint8_t block_size = *buffer++; // Normalmente, blockSize == 4
|
|
||||||
buffer += block_size; // Saltamos los 4 bytes del bloque fijo
|
|
||||||
// Saltar los sub-bloques
|
|
||||||
uint8_t sub_block_size = *buffer++;
|
|
||||||
while (sub_block_size != 0) {
|
|
||||||
buffer += sub_block_size;
|
|
||||||
sub_block_size = *buffer++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case APPLICATION_EXTENSION: // 0xFF
|
|
||||||
case COMMENT_EXTENSION: // 0xFE
|
|
||||||
case PLAINTEXT_EXTENSION: // 0x01
|
|
||||||
{
|
|
||||||
// Para estas extensiones, saltamos el bloque fijo y los sub-bloques.
|
|
||||||
uint8_t block_size = *buffer++;
|
|
||||||
buffer += block_size;
|
|
||||||
uint8_t sub_block_size = *buffer++;
|
|
||||||
while (sub_block_size != 0) {
|
|
||||||
buffer += sub_block_size;
|
|
||||||
sub_block_size = *buffer++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
// Si la etiqueta de extensión es desconocida, saltarla también:
|
|
||||||
uint8_t block_size = *buffer++;
|
|
||||||
buffer += block_size;
|
|
||||||
uint8_t sub_block_size = *buffer++;
|
|
||||||
while (sub_block_size != 0) {
|
|
||||||
buffer += sub_block_size;
|
|
||||||
sub_block_size = *buffer++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (block_type == IMAGE_DESCRIPTOR) {
|
code |= (bit << i);
|
||||||
// Procesar el Image Descriptor y retornar los datos de imagen
|
}
|
||||||
return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encuentra el primer byte de una cadena del diccionario
|
||||||
|
inline auto findFirstByte(const std::vector<DictionaryEntry>& dictionary, int code) -> uint8_t {
|
||||||
|
int ptr = code;
|
||||||
|
while (dictionary[ptr].prev != -1) {
|
||||||
|
ptr = dictionary[ptr].prev;
|
||||||
|
}
|
||||||
|
return dictionary[ptr].byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agrega una nueva entrada al diccionario
|
||||||
|
inline void addDictionaryEntry(std::vector<DictionaryEntry>& dictionary, int& dictionary_ind, int& code_length, int prev, int code) {
|
||||||
|
uint8_t first_byte;
|
||||||
|
if (code == dictionary_ind) {
|
||||||
|
first_byte = findFirstByte(dictionary, prev);
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Unrecognized block type " << std::hex << static_cast<int>(block_type) << '\n';
|
first_byte = findFirstByte(dictionary, code);
|
||||||
return std::vector<uint8_t>{};
|
}
|
||||||
|
|
||||||
|
dictionary[dictionary_ind].byte = first_byte;
|
||||||
|
dictionary[dictionary_ind].prev = prev;
|
||||||
|
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
|
||||||
|
dictionary_ind++;
|
||||||
|
|
||||||
|
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
|
||||||
|
code_length++;
|
||||||
|
dictionary.resize(1 << (code_length + 1));
|
||||||
}
|
}
|
||||||
block_type = *buffer++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::vector<uint8_t>{};
|
// Escribe la cadena decodificada al buffer de salida
|
||||||
}
|
inline auto writeDecodedString(const std::vector<DictionaryEntry>& dictionary, int code, uint8_t*& out) -> int {
|
||||||
|
int cur_code = code;
|
||||||
|
int match_len = dictionary[cur_code].len;
|
||||||
|
while (cur_code != -1) {
|
||||||
|
out[dictionary[cur_code].len - 1] = dictionary[cur_code].byte;
|
||||||
|
if (dictionary[cur_code].prev == cur_code) {
|
||||||
|
std::cerr << "Internal error; self-reference detected." << '\n';
|
||||||
|
throw std::runtime_error("Internal error in decompress: self-reference");
|
||||||
|
}
|
||||||
|
cur_code = dictionary[cur_code].prev;
|
||||||
|
}
|
||||||
|
out += match_len;
|
||||||
|
return match_len;
|
||||||
|
}
|
||||||
|
|
||||||
auto Gif::loadGif(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t> {
|
void Gif::decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out) {
|
||||||
return processGifStream(buffer, w, h);
|
// Verifica que el code_length tenga un rango razonable.
|
||||||
}
|
if (code_length < 2 || code_length > 12) {
|
||||||
|
throw std::runtime_error("Invalid LZW code length");
|
||||||
|
}
|
||||||
|
|
||||||
|
int prev = -1;
|
||||||
|
std::vector<DictionaryEntry> dictionary;
|
||||||
|
int dictionary_ind;
|
||||||
|
unsigned int mask = 0x01;
|
||||||
|
int reset_code_length = code_length;
|
||||||
|
int clear_code = 1 << code_length;
|
||||||
|
int stop_code = clear_code + 1;
|
||||||
|
|
||||||
|
// Inicializamos el diccionario con el tamaño correspondiente.
|
||||||
|
initializeDictionary(dictionary, code_length, dictionary_ind);
|
||||||
|
|
||||||
|
// Bucle principal: procesar el stream comprimido.
|
||||||
|
while (input_length > 0) {
|
||||||
|
int code = readNextCode(input, input_length, mask, code_length);
|
||||||
|
|
||||||
|
if (code == clear_code) {
|
||||||
|
// Reinicia el diccionario.
|
||||||
|
code_length = reset_code_length;
|
||||||
|
initializeDictionary(dictionary, code_length, dictionary_ind);
|
||||||
|
prev = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code == stop_code) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev > -1 && code_length < 12) {
|
||||||
|
if (code > dictionary_ind) {
|
||||||
|
std::cerr << "code = " << std::hex << code
|
||||||
|
<< ", but dictionary_ind = " << dictionary_ind << '\n';
|
||||||
|
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
||||||
|
}
|
||||||
|
|
||||||
|
addDictionaryEntry(dictionary, dictionary_ind, code_length, prev, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = code;
|
||||||
|
|
||||||
|
// Verifica que 'code' sea un índice válido antes de usarlo.
|
||||||
|
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
|
||||||
|
std::cerr << "Invalid LZW code " << code
|
||||||
|
<< ", dictionary size " << dictionary.size() << '\n';
|
||||||
|
throw std::runtime_error("LZW error: invalid code encountered");
|
||||||
|
}
|
||||||
|
|
||||||
|
writeDecodedString(dictionary, code, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> {
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
uint8_t block_size = *buffer;
|
||||||
|
buffer++;
|
||||||
|
while (block_size != 0) {
|
||||||
|
data.insert(data.end(), buffer, buffer + block_size);
|
||||||
|
buffer += block_size;
|
||||||
|
block_size = *buffer;
|
||||||
|
buffer++;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Gif::processImageDescriptor(const uint8_t*& buffer, const std::vector<RGB>& gct, int resolution_bits) -> std::vector<uint8_t> {
|
||||||
|
ImageDescriptor image_descriptor;
|
||||||
|
// Lee 9 bytes para el image descriptor.
|
||||||
|
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
|
||||||
|
|
||||||
|
uint8_t lzw_code_size;
|
||||||
|
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
|
||||||
|
|
||||||
|
std::vector<uint8_t> compressed_data = readSubBlocks(buffer);
|
||||||
|
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
|
||||||
|
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
|
||||||
|
|
||||||
|
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
|
||||||
|
return uncompressed_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Gif::loadPalette(const uint8_t* buffer) -> std::vector<uint32_t> {
|
||||||
|
uint8_t header[6];
|
||||||
|
std::memcpy(header, buffer, 6);
|
||||||
|
buffer += 6;
|
||||||
|
|
||||||
|
ScreenDescriptor screen_descriptor;
|
||||||
|
std::memcpy(&screen_descriptor, buffer, sizeof(ScreenDescriptor));
|
||||||
|
buffer += sizeof(ScreenDescriptor);
|
||||||
|
|
||||||
|
std::vector<uint32_t> global_color_table;
|
||||||
|
if ((screen_descriptor.fields & 0x80) != 0) {
|
||||||
|
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
||||||
|
global_color_table.resize(global_color_table_size);
|
||||||
|
for (int i = 0; i < global_color_table_size; ++i) {
|
||||||
|
uint8_t r = buffer[0];
|
||||||
|
uint8_t g = buffer[1];
|
||||||
|
uint8_t b = buffer[2];
|
||||||
|
global_color_table[i] = (r << 16) | (g << 8) | b;
|
||||||
|
buffer += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return global_color_table;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Gif::processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t> {
|
||||||
|
// Leer la cabecera de 6 bytes ("GIF87a" o "GIF89a")
|
||||||
|
uint8_t header[6];
|
||||||
|
std::memcpy(header, buffer, 6);
|
||||||
|
buffer += 6;
|
||||||
|
|
||||||
|
// Opcional: Validar header
|
||||||
|
std::string header_str(reinterpret_cast<char*>(header), 6);
|
||||||
|
if (header_str != "GIF87a" && header_str != "GIF89a") {
|
||||||
|
throw std::runtime_error("Formato de archivo GIF inválido.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leer el Screen Descriptor (7 bytes, empaquetado sin padding)
|
||||||
|
ScreenDescriptor screen_descriptor;
|
||||||
|
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
|
||||||
|
|
||||||
|
// Asigna ancho y alto
|
||||||
|
w = screen_descriptor.width;
|
||||||
|
h = screen_descriptor.height;
|
||||||
|
|
||||||
|
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
|
||||||
|
std::vector<RGB> global_color_table;
|
||||||
|
if ((screen_descriptor.fields & 0x80) != 0) {
|
||||||
|
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
||||||
|
global_color_table.resize(global_color_table_size);
|
||||||
|
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
|
||||||
|
buffer += 3 * global_color_table_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supongamos que 'buffer' es el puntero actual y TRAILER es 0x3B
|
||||||
|
uint8_t block_type = *buffer++;
|
||||||
|
while (block_type != TRAILER) {
|
||||||
|
if (block_type == EXTENSION_INTRODUCER) // 0x21
|
||||||
|
{
|
||||||
|
// Se lee la etiqueta de extensión, la cual indica el tipo de extensión.
|
||||||
|
uint8_t extension_label = *buffer++;
|
||||||
|
switch (extension_label) {
|
||||||
|
case GRAPHIC_CONTROL: // 0xF9
|
||||||
|
{
|
||||||
|
// Procesar Graphic Control Extension:
|
||||||
|
uint8_t block_size = *buffer++; // Normalmente, blockSize == 4
|
||||||
|
buffer += block_size; // Saltamos los 4 bytes del bloque fijo
|
||||||
|
// Saltar los sub-bloques
|
||||||
|
uint8_t sub_block_size = *buffer++;
|
||||||
|
while (sub_block_size != 0) {
|
||||||
|
buffer += sub_block_size;
|
||||||
|
sub_block_size = *buffer++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case APPLICATION_EXTENSION: // 0xFF
|
||||||
|
case COMMENT_EXTENSION: // 0xFE
|
||||||
|
case PLAINTEXT_EXTENSION: // 0x01
|
||||||
|
{
|
||||||
|
// Para estas extensiones, saltamos el bloque fijo y los sub-bloques.
|
||||||
|
uint8_t block_size = *buffer++;
|
||||||
|
buffer += block_size;
|
||||||
|
uint8_t sub_block_size = *buffer++;
|
||||||
|
while (sub_block_size != 0) {
|
||||||
|
buffer += sub_block_size;
|
||||||
|
sub_block_size = *buffer++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// Si la etiqueta de extensión es desconocida, saltarla también:
|
||||||
|
uint8_t block_size = *buffer++;
|
||||||
|
buffer += block_size;
|
||||||
|
uint8_t sub_block_size = *buffer++;
|
||||||
|
while (sub_block_size != 0) {
|
||||||
|
buffer += sub_block_size;
|
||||||
|
sub_block_size = *buffer++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (block_type == IMAGE_DESCRIPTOR) {
|
||||||
|
// Procesar el Image Descriptor y retornar los datos de imagen
|
||||||
|
return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
|
||||||
|
} else {
|
||||||
|
std::cerr << "Unrecognized block type " << std::hex << static_cast<int>(block_type) << '\n';
|
||||||
|
return std::vector<uint8_t>{};
|
||||||
|
}
|
||||||
|
block_type = *buffer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::vector<uint8_t>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Gif::loadGif(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t> {
|
||||||
|
return processGifStream(buffer, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace GIF
|
} // namespace GIF
|
||||||
|
|||||||
@@ -5,67 +5,67 @@
|
|||||||
|
|
||||||
namespace GIF {
|
namespace GIF {
|
||||||
|
|
||||||
// Constantes definidas con constexpr, en lugar de macros
|
// Constantes definidas con constexpr, en lugar de macros
|
||||||
constexpr uint8_t EXTENSION_INTRODUCER = 0x21;
|
constexpr uint8_t EXTENSION_INTRODUCER = 0x21;
|
||||||
constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C;
|
constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C;
|
||||||
constexpr uint8_t TRAILER = 0x3B;
|
constexpr uint8_t TRAILER = 0x3B;
|
||||||
constexpr uint8_t GRAPHIC_CONTROL = 0xF9;
|
constexpr uint8_t GRAPHIC_CONTROL = 0xF9;
|
||||||
constexpr uint8_t APPLICATION_EXTENSION = 0xFF;
|
constexpr uint8_t APPLICATION_EXTENSION = 0xFF;
|
||||||
constexpr uint8_t COMMENT_EXTENSION = 0xFE;
|
constexpr uint8_t COMMENT_EXTENSION = 0xFE;
|
||||||
constexpr uint8_t PLAINTEXT_EXTENSION = 0x01;
|
constexpr uint8_t PLAINTEXT_EXTENSION = 0x01;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct ScreenDescriptor {
|
struct ScreenDescriptor {
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
uint8_t fields;
|
uint8_t fields;
|
||||||
uint8_t background_color_index;
|
uint8_t background_color_index;
|
||||||
uint8_t pixel_aspect_ratio;
|
uint8_t pixel_aspect_ratio;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RGB {
|
struct RGB {
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImageDescriptor {
|
struct ImageDescriptor {
|
||||||
uint16_t image_left_position;
|
uint16_t image_left_position;
|
||||||
uint16_t image_top_position;
|
uint16_t image_top_position;
|
||||||
uint16_t image_width;
|
uint16_t image_width;
|
||||||
uint16_t image_height;
|
uint16_t image_height;
|
||||||
uint8_t fields;
|
uint8_t fields;
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
struct DictionaryEntry {
|
struct DictionaryEntry {
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
int prev;
|
int prev;
|
||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Extension {
|
struct Extension {
|
||||||
uint8_t extension_code;
|
uint8_t extension_code;
|
||||||
uint8_t block_size;
|
uint8_t block_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphicControlExtension {
|
struct GraphicControlExtension {
|
||||||
uint8_t fields;
|
uint8_t fields;
|
||||||
uint16_t delay_time;
|
uint16_t delay_time;
|
||||||
uint8_t transparent_color_index;
|
uint8_t transparent_color_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ApplicationExtension {
|
struct ApplicationExtension {
|
||||||
uint8_t application_id[8];
|
uint8_t application_id[8];
|
||||||
uint8_t version[3];
|
uint8_t version[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlaintextExtension {
|
struct PlaintextExtension {
|
||||||
uint16_t left, top, width, height;
|
uint16_t left, top, width, height;
|
||||||
uint8_t cell_width, cell_height;
|
uint8_t cell_width, cell_height;
|
||||||
uint8_t foreground_color, background_color;
|
uint8_t foreground_color, background_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Gif {
|
class Gif {
|
||||||
public:
|
public:
|
||||||
// Descompone (uncompress) el bloque comprimido usando LZW.
|
// Descompone (uncompress) el bloque comprimido usando LZW.
|
||||||
// Este método puede lanzar std::runtime_error en caso de error.
|
// Este método puede lanzar std::runtime_error en caso de error.
|
||||||
static void decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out);
|
static void decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out);
|
||||||
@@ -78,7 +78,7 @@ class Gif {
|
|||||||
// asigna el ancho y alto mediante referencias.
|
// asigna el ancho y alto mediante referencias.
|
||||||
static auto loadGif(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t>;
|
static auto loadGif(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Lee los sub-bloques de datos y los acumula en un std::vector<uint8_t>.
|
// Lee los sub-bloques de datos y los acumula en un std::vector<uint8_t>.
|
||||||
static auto readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t>;
|
static auto readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t>;
|
||||||
|
|
||||||
@@ -87,6 +87,6 @@ class Gif {
|
|||||||
|
|
||||||
// Procesa el stream completo del GIF y devuelve los datos sin comprimir.
|
// Procesa el stream completo del GIF y devuelve los datos sin comprimir.
|
||||||
static auto processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t>;
|
static auto processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t>;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace GIF
|
} // namespace GIF
|
||||||
|
|||||||
@@ -8,35 +8,35 @@ class Surface;
|
|||||||
// Efecto de revelado pixel a pixel por filas, de arriba a abajo.
|
// Efecto de revelado pixel a pixel por filas, de arriba a abajo.
|
||||||
// Cada fila se revela en num_steps pasos, con píxeles en orden aleatorio u ordenado (bisección).
|
// Cada fila se revela en num_steps pasos, con píxeles en orden aleatorio u ordenado (bisección).
|
||||||
class PixelReveal {
|
class PixelReveal {
|
||||||
public:
|
public:
|
||||||
// Modo de revelado: aleatorio por fila o en orden de bisección (dithering ordenado 1D)
|
// Modo de revelado: aleatorio por fila o en orden de bisección (dithering ordenado 1D)
|
||||||
enum class RevealMode { RANDOM,
|
enum class RevealMode { RANDOM,
|
||||||
ORDERED };
|
ORDERED };
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4, bool reverse = false, RevealMode mode = RevealMode::RANDOM);
|
PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4, bool reverse = false, RevealMode mode = RevealMode::RANDOM);
|
||||||
|
|
||||||
// Destructor definido en el .cpp para que unique_ptr<Surface> funcione con forward declaration
|
// Destructor definido en el .cpp para que unique_ptr<Surface> funcione con forward declaration
|
||||||
~PixelReveal();
|
~PixelReveal();
|
||||||
|
|
||||||
// Actualiza el estado del revelado según el tiempo transcurrido
|
// Actualiza el estado del revelado según el tiempo transcurrido
|
||||||
void update(float time_active);
|
void update(float time_active);
|
||||||
|
|
||||||
// Dibuja la máscara de revelado en la posición indicada
|
// Dibuja la máscara de revelado en la posición indicada
|
||||||
void render(int dst_x, int dst_y) const;
|
void render(int dst_x, int dst_y) const;
|
||||||
|
|
||||||
// Indica si el revelado ha completado todas las filas
|
// Indica si el revelado ha completado todas las filas
|
||||||
[[nodiscard]] auto isComplete() const -> bool;
|
[[nodiscard]] auto isComplete() const -> bool;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Surface> cover_surface_; // Máscara negra que se va haciendo transparente
|
std::shared_ptr<Surface> cover_surface_; // Máscara negra que se va haciendo transparente
|
||||||
std::vector<std::vector<int>> reveal_order_; // Orden de columnas por fila (aleatorio u ordenado por bisección)
|
std::vector<std::vector<int>> reveal_order_; // Orden de columnas por fila (aleatorio u ordenado por bisección)
|
||||||
std::vector<int> row_step_; // Paso actual de revelado por fila (0..num_steps_)
|
std::vector<int> row_step_; // Paso actual de revelado por fila (0..num_steps_)
|
||||||
int width_;
|
int width_;
|
||||||
int height_;
|
int height_;
|
||||||
float pixels_per_second_; // Filas reveladas por segundo
|
float pixels_per_second_; // Filas reveladas por segundo
|
||||||
float step_duration_; // Segundos por paso dentro de una fila
|
float step_duration_; // Segundos por paso dentro de una fila
|
||||||
int num_steps_; // Número de pasos de revelado por fila
|
int num_steps_; // Número de pasos de revelado por fila
|
||||||
bool reverse_; // Si true: transparente → negro (ocultar); si false: negro → transparente (revelar)
|
bool reverse_; // Si true: transparente → negro (ocultar); si false: negro → transparente (revelar)
|
||||||
RevealMode mode_; // Modo de revelado: aleatorio u ordenado por bisección
|
RevealMode mode_; // Modo de revelado: aleatorio u ordenado por bisección
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,154 +12,154 @@
|
|||||||
class Surface;
|
class Surface;
|
||||||
class Text;
|
class Text;
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
class ShaderBackend;
|
class ShaderBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Screen {
|
class Screen {
|
||||||
public:
|
public:
|
||||||
// Tipos de filtro
|
// Tipos de filtro
|
||||||
enum class Filter : Uint32 {
|
enum class Filter : Uint32 {
|
||||||
NEAREST = 0,
|
NEAREST = 0,
|
||||||
LINEAR = 1,
|
LINEAR = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Singleton
|
// Singleton
|
||||||
static void init(); // Crea el singleton
|
static void init(); // Crea el singleton
|
||||||
static void destroy(); // Destruye el singleton
|
static void destroy(); // Destruye el singleton
|
||||||
static auto get() -> Screen*; // Obtiene el singleton
|
static auto get() -> Screen*; // Obtiene el singleton
|
||||||
|
|
||||||
// Renderizado
|
// Renderizado
|
||||||
void clearRenderer(Color color = {0x00, 0x00, 0x00}); // Limpia el renderer
|
void clearRenderer(Color color = {0x00, 0x00, 0x00}); // Limpia el renderer
|
||||||
void clearSurface(Uint8 index); // Limpia la game_surface_
|
void clearSurface(Uint8 index); // Limpia la game_surface_
|
||||||
void start(); // Prepara para empezar a dibujar en la textura de juego
|
void start(); // Prepara para empezar a dibujar en la textura de juego
|
||||||
void render(); // Vuelca el contenido del renderizador en pantalla
|
void render(); // Vuelca el contenido del renderizador en pantalla
|
||||||
void update(float delta_time); // Actualiza la lógica de la clase
|
void update(float delta_time); // Actualiza la lógica de la clase
|
||||||
|
|
||||||
// Video y ventana
|
// Video y ventana
|
||||||
void setVideoMode(bool mode); // Establece el modo de video
|
void setVideoMode(bool mode); // Establece el modo de video
|
||||||
void toggleVideoMode(); // Cambia entre pantalla completa y ventana
|
void toggleVideoMode(); // Cambia entre pantalla completa y ventana
|
||||||
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
|
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
|
||||||
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
|
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
|
||||||
auto decWindowZoom() -> bool; // Reduce el tamaño de la ventana
|
auto decWindowZoom() -> bool; // Reduce el tamaño de la ventana
|
||||||
auto incWindowZoom() -> bool; // Aumenta el tamaño de la ventana
|
auto incWindowZoom() -> bool; // Aumenta el tamaño de la ventana
|
||||||
void show(); // Muestra la ventana
|
void show(); // Muestra la ventana
|
||||||
void hide(); // Oculta la ventana
|
void hide(); // Oculta la ventana
|
||||||
|
|
||||||
// Borde
|
// Borde
|
||||||
void setBorderColor(Uint8 color); // Cambia el color del borde
|
void setBorderColor(Uint8 color); // Cambia el color del borde
|
||||||
static void setBorderWidth(int width); // Establece el ancho del borde
|
static void setBorderWidth(int width); // Establece el ancho del borde
|
||||||
static void setBorderHeight(int height); // Establece el alto del borde
|
static void setBorderHeight(int height); // Establece el alto del borde
|
||||||
static void setBorderEnabled(bool value); // Establece si se ha de ver el borde
|
static void setBorderEnabled(bool value); // Establece si se ha de ver el borde
|
||||||
void toggleBorder(); // Cambia entre borde visible y no visible
|
void toggleBorder(); // Cambia entre borde visible y no visible
|
||||||
|
|
||||||
// Paletas y PostFX
|
// Paletas y PostFX
|
||||||
void nextPalette(); // Cambia a la siguiente paleta
|
void nextPalette(); // Cambia a la siguiente paleta
|
||||||
void previousPalette(); // Cambia a la paleta anterior
|
void previousPalette(); // Cambia a la paleta anterior
|
||||||
void setPalete(); // Establece la paleta actual
|
void setPalete(); // Establece la paleta actual
|
||||||
void togglePostFX(); // Cambia el estado del PostFX
|
void togglePostFX(); // Cambia el estado del PostFX
|
||||||
void reloadPostFX(); // Recarga el shader del preset actual sin toggle
|
void reloadPostFX(); // Recarga el shader del preset actual sin toggle
|
||||||
|
|
||||||
// Surfaces y notificaciones
|
// Surfaces y notificaciones
|
||||||
void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces
|
void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces
|
||||||
void setNotificationsEnabled(bool value); // Establece la visibilidad de las notificaciones
|
void setNotificationsEnabled(bool value); // Establece la visibilidad de las notificaciones
|
||||||
void toggleDebugInfo(); // Activa o desactiva la información de debug
|
void toggleDebugInfo(); // Activa o desactiva la información de debug
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
auto getRenderer() -> SDL_Renderer*;
|
auto getRenderer() -> SDL_Renderer*;
|
||||||
auto getRendererSurface() -> std::shared_ptr<Surface>;
|
auto getRendererSurface() -> std::shared_ptr<Surface>;
|
||||||
auto getBorderSurface() -> std::shared_ptr<Surface>;
|
auto getBorderSurface() -> std::shared_ptr<Surface>;
|
||||||
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; }
|
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; }
|
||||||
[[nodiscard]] auto getGameSurfaceDstRect() const -> SDL_FRect { return game_surface_dstrect_; }
|
[[nodiscard]] auto getGameSurfaceDstRect() const -> SDL_FRect { return game_surface_dstrect_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Estructuras
|
// Estructuras
|
||||||
struct DisplayMonitor {
|
struct DisplayMonitor {
|
||||||
std::string name;
|
std::string name;
|
||||||
int width{0};
|
int width{0};
|
||||||
int height{0};
|
int height{0};
|
||||||
int refresh_rate{0};
|
int refresh_rate{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FPS {
|
struct FPS {
|
||||||
Uint32 ticks{0}; // Tiempo en milisegundos desde que se comenzó a contar
|
Uint32 ticks{0}; // Tiempo en milisegundos desde que se comenzó a contar
|
||||||
int frame_count{0}; // Número acumulado de frames en el intervalo
|
int frame_count{0}; // Número acumulado de frames en el intervalo
|
||||||
int last_value{0}; // Número de frames calculado en el último segundo
|
int last_value{0}; // Número de frames calculado en el último segundo
|
||||||
|
|
||||||
void increment() {
|
void increment() {
|
||||||
frame_count++;
|
frame_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto calculate(Uint32 current_ticks) -> int {
|
auto calculate(Uint32 current_ticks) -> int {
|
||||||
if (current_ticks - ticks >= 1000) {
|
if (current_ticks - ticks >= 1000) {
|
||||||
last_value = frame_count;
|
last_value = frame_count;
|
||||||
frame_count = 0;
|
frame_count = 0;
|
||||||
ticks = current_ticks;
|
ticks = current_ticks;
|
||||||
}
|
}
|
||||||
return last_value;
|
return last_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constantes
|
// Constantes
|
||||||
static constexpr int WINDOWS_DECORATIONS = 35; // Decoraciones de la ventana
|
static constexpr int WINDOWS_DECORATIONS = 35; // Decoraciones de la ventana
|
||||||
|
|
||||||
// Singleton
|
// Singleton
|
||||||
static Screen* screen;
|
static Screen* screen;
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
void renderNotifications() const; // Dibuja las notificaciones
|
void renderNotifications() const; // Dibuja las notificaciones
|
||||||
void adjustWindowSize(); // Calcula el tamaño de la ventana
|
void adjustWindowSize(); // Calcula el tamaño de la ventana
|
||||||
void adjustRenderLogicalSize(); // Ajusta el tamaño lógico del renderizador
|
void adjustRenderLogicalSize(); // Ajusta el tamaño lógico del renderizador
|
||||||
void processPaletteList(); // Extrae los nombres de las paletas
|
void processPaletteList(); // Extrae los nombres de las paletas
|
||||||
void surfaceToTexture(); // Copia la surface a la textura
|
void surfaceToTexture(); // Copia la surface a la textura
|
||||||
void textureToRenderer(); // Copia la textura al renderizador
|
void textureToRenderer(); // Copia la textura al renderizador
|
||||||
void renderOverlays(); // Renderiza todos los overlays
|
void renderOverlays(); // Renderiza todos los overlays
|
||||||
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
|
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
|
||||||
void initShaders(); // Inicializa los shaders
|
void initShaders(); // Inicializa los shaders
|
||||||
void applyCurrentPostFXPreset(); // Aplica los parámetros del preset actual al backend
|
void applyCurrentPostFXPreset(); // Aplica los parámetros del preset actual al backend
|
||||||
void renderInfo() const; // Muestra información por pantalla
|
void renderInfo() const; // Muestra información por pantalla
|
||||||
void getDisplayInfo(); // Obtiene información sobre la pantalla
|
void getDisplayInfo(); // Obtiene información sobre la pantalla
|
||||||
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
||||||
void createText(); // Crea el objeto de texto
|
void createText(); // Crea el objeto de texto
|
||||||
|
|
||||||
// Constructor y destructor
|
// Constructor y destructor
|
||||||
Screen();
|
Screen();
|
||||||
~Screen();
|
~Screen();
|
||||||
|
|
||||||
// Objetos SDL
|
// Objetos SDL
|
||||||
SDL_Window* window_{nullptr}; // Ventana de la aplicación
|
SDL_Window* window_{nullptr}; // Ventana de la aplicación
|
||||||
SDL_Renderer* renderer_{nullptr}; // Renderizador de la ventana
|
SDL_Renderer* renderer_{nullptr}; // Renderizador de la ventana
|
||||||
SDL_Texture* game_texture_{nullptr}; // Textura donde se dibuja el juego
|
SDL_Texture* game_texture_{nullptr}; // Textura donde se dibuja el juego
|
||||||
SDL_Texture* border_texture_{nullptr}; // Textura donde se dibuja el borde del juego
|
SDL_Texture* border_texture_{nullptr}; // Textura donde se dibuja el borde del juego
|
||||||
|
|
||||||
// Surfaces y renderizado
|
// Surfaces y renderizado
|
||||||
std::shared_ptr<Surface> game_surface_; // Surface principal del juego
|
std::shared_ptr<Surface> game_surface_; // Surface principal del juego
|
||||||
std::shared_ptr<Surface> border_surface_; // Surface para el borde de la pantalla
|
std::shared_ptr<Surface> border_surface_; // Surface para el borde de la pantalla
|
||||||
std::shared_ptr<std::shared_ptr<Surface>> renderer_surface_; // Puntero a la Surface activa
|
std::shared_ptr<std::shared_ptr<Surface>> renderer_surface_; // Puntero a la Surface activa
|
||||||
std::unique_ptr<Rendering::ShaderBackend> shader_backend_; // Backend de shaders (OpenGL/Metal/Vulkan)
|
std::unique_ptr<Rendering::ShaderBackend> shader_backend_; // Backend de shaders (OpenGL/Metal/Vulkan)
|
||||||
std::shared_ptr<Text> text_; // Objeto para escribir texto
|
std::shared_ptr<Text> text_; // Objeto para escribir texto
|
||||||
|
|
||||||
// Configuración de ventana y pantalla
|
// Configuración de ventana y pantalla
|
||||||
int window_width_{0}; // Ancho de la pantalla o ventana
|
int window_width_{0}; // Ancho de la pantalla o ventana
|
||||||
int window_height_{0}; // Alto de la pantalla o ventana
|
int window_height_{0}; // Alto de la pantalla o ventana
|
||||||
SDL_FRect game_surface_dstrect_; // Coordenadas donde se dibuja la textura del juego
|
SDL_FRect game_surface_dstrect_; // Coordenadas donde se dibuja la textura del juego
|
||||||
|
|
||||||
// Paletas y colores
|
// Paletas y colores
|
||||||
Uint8 border_color_{0}; // Color del borde
|
Uint8 border_color_{0}; // Color del borde
|
||||||
std::vector<std::string> palettes_; // Listado de ficheros de paleta disponibles
|
std::vector<std::string> palettes_; // Listado de ficheros de paleta disponibles
|
||||||
Uint8 current_palette_{0}; // Índice para el vector de paletas
|
Uint8 current_palette_{0}; // Índice para el vector de paletas
|
||||||
|
|
||||||
// Estado y configuración
|
// Estado y configuración
|
||||||
bool notifications_enabled_{false}; // Indica si se muestran las notificaciones
|
bool notifications_enabled_{false}; // Indica si se muestran las notificaciones
|
||||||
FPS fps_; // Gestor de frames por segundo
|
FPS fps_; // Gestor de frames por segundo
|
||||||
DisplayMonitor display_monitor_; // Información de la pantalla
|
DisplayMonitor display_monitor_; // Información de la pantalla
|
||||||
|
|
||||||
// Shaders
|
// Shaders
|
||||||
std::string info_resolution_; // Texto con la información de la pantalla
|
std::string info_resolution_; // Texto con la información de la pantalla
|
||||||
std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
|
std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
bool show_debug_info_{true}; // Indica si ha de mostrar la información de debug
|
bool show_debug_info_{true}; // Indica si ha de mostrar la información de debug
|
||||||
#else
|
#else
|
||||||
bool show_debug_info_{false}; // Indica si ha de mostrar la información de debug
|
bool show_debug_info_{false}; // Indica si ha de mostrar la información de debug
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -162,395 +162,395 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
|||||||
|
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Destructor
|
// Destructor
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
SDL3GPUShader::~SDL3GPUShader() {
|
SDL3GPUShader::~SDL3GPUShader() {
|
||||||
destroy();
|
destroy();
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// init
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
auto SDL3GPUShader::init(SDL_Window* window,
|
|
||||||
SDL_Texture* texture,
|
|
||||||
const std::string& /*vertex_source*/,
|
|
||||||
const std::string& /*fragment_source*/) -> bool {
|
|
||||||
// Si ya estaba inicializado (p.ej. al cambiar borde), liberar recursos
|
|
||||||
// de textura/pipeline pero mantener el device vivo para evitar conflictos
|
|
||||||
// con SDL_Renderer en Windows/Vulkan.
|
|
||||||
if (is_initialized_) {
|
|
||||||
cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window_ = window;
|
// ---------------------------------------------------------------------------
|
||||||
|
// init
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
auto SDL3GPUShader::init(SDL_Window* window,
|
||||||
|
SDL_Texture* texture,
|
||||||
|
const std::string& /*vertex_source*/,
|
||||||
|
const std::string& /*fragment_source*/) -> bool {
|
||||||
|
// Si ya estaba inicializado (p.ej. al cambiar borde), liberar recursos
|
||||||
|
// de textura/pipeline pero mantener el device vivo para evitar conflictos
|
||||||
|
// con SDL_Renderer en Windows/Vulkan.
|
||||||
|
if (is_initialized_) {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
// Dimensions from the SDL_Texture placeholder
|
window_ = window;
|
||||||
float fw = 0.0F;
|
|
||||||
float fh = 0.0F;
|
|
||||||
SDL_GetTextureSize(texture, &fw, &fh);
|
|
||||||
tex_width_ = static_cast<int>(fw);
|
|
||||||
tex_height_ = static_cast<int>(fh);
|
|
||||||
uniforms_.screen_height = fh; // Altura lógica del juego (no el swapchain físico)
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// Dimensions from the SDL_Texture placeholder
|
||||||
// 1. Create GPU device (solo si no existe ya)
|
float fw = 0.0F;
|
||||||
// ----------------------------------------------------------------
|
float fh = 0.0F;
|
||||||
if (device_ == nullptr) {
|
SDL_GetTextureSize(texture, &fw, &fh);
|
||||||
#ifdef __APPLE__
|
tex_width_ = static_cast<int>(fw);
|
||||||
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
|
tex_height_ = static_cast<int>(fh);
|
||||||
#else
|
uniforms_.screen_height = fh; // Altura lógica del juego (no el swapchain físico)
|
||||||
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_SPIRV;
|
|
||||||
#endif
|
// ----------------------------------------------------------------
|
||||||
device_ = SDL_CreateGPUDevice(PREFERRED, false, nullptr);
|
// 1. Create GPU device (solo si no existe ya)
|
||||||
|
// ----------------------------------------------------------------
|
||||||
if (device_ == nullptr) {
|
if (device_ == nullptr) {
|
||||||
SDL_Log("SDL3GPUShader: SDL_CreateGPUDevice failed: %s", SDL_GetError());
|
#ifdef __APPLE__
|
||||||
|
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB;
|
||||||
|
#else
|
||||||
|
const SDL_GPUShaderFormat PREFERRED = SDL_GPU_SHADERFORMAT_SPIRV;
|
||||||
|
#endif
|
||||||
|
device_ = SDL_CreateGPUDevice(PREFERRED, false, nullptr);
|
||||||
|
if (device_ == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: SDL_CreateGPUDevice failed: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SDL_Log("SDL3GPUShader: driver = %s", SDL_GetGPUDeviceDriver(device_));
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// 2. Claim window (una sola vez — no liberar hasta destroy())
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
if (!SDL_ClaimWindowForGPUDevice(device_, window_)) {
|
||||||
|
SDL_Log("SDL3GPUShader: SDL_ClaimWindowForGPUDevice failed: %s", SDL_GetError());
|
||||||
|
SDL_DestroyGPUDevice(device_);
|
||||||
|
device_ = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, vsync_ ? SDL_GPU_PRESENTMODE_VSYNC : SDL_GPU_PRESENTMODE_IMMEDIATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// 3. Create scene texture (upload target + sampler source)
|
||||||
|
// Format: B8G8R8A8_UNORM matches SDL ARGB8888 byte layout on LE
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
SDL_GPUTextureCreateInfo tex_info = {};
|
||||||
|
tex_info.type = SDL_GPU_TEXTURETYPE_2D;
|
||||||
|
tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
|
||||||
|
tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
||||||
|
tex_info.width = static_cast<Uint32>(tex_width_);
|
||||||
|
tex_info.height = static_cast<Uint32>(tex_height_);
|
||||||
|
tex_info.layer_count_or_depth = 1;
|
||||||
|
tex_info.num_levels = 1;
|
||||||
|
scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info);
|
||||||
|
if (scene_texture_ == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: failed to create scene texture: %s", SDL_GetError());
|
||||||
|
cleanup();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SDL_Log("SDL3GPUShader: driver = %s", SDL_GetGPUDeviceDriver(device_));
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
// 2. Claim window (una sola vez — no liberar hasta destroy())
|
// 4. Create upload transfer buffer (CPU → GPU, size = w*h*4 bytes)
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
if (!SDL_ClaimWindowForGPUDevice(device_, window_)) {
|
SDL_GPUTransferBufferCreateInfo tb_info = {};
|
||||||
SDL_Log("SDL3GPUShader: SDL_ClaimWindowForGPUDevice failed: %s", SDL_GetError());
|
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
||||||
|
tb_info.size = static_cast<Uint32>(tex_width_ * tex_height_ * 4);
|
||||||
|
upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info);
|
||||||
|
if (upload_buffer_ == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: failed to create upload buffer: %s", SDL_GetError());
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// 5. Create nearest-neighbour sampler (retro pixel art)
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
SDL_GPUSamplerCreateInfo samp_info = {};
|
||||||
|
samp_info.min_filter = SDL_GPU_FILTER_NEAREST;
|
||||||
|
samp_info.mag_filter = SDL_GPU_FILTER_NEAREST;
|
||||||
|
samp_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
||||||
|
samp_info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||||||
|
samp_info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||||||
|
samp_info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||||||
|
sampler_ = SDL_CreateGPUSampler(device_, &samp_info);
|
||||||
|
if (sampler_ == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: failed to create sampler: %s", SDL_GetError());
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// 6. Create PostFX graphics pipeline
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
if (!createPipeline()) {
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_initialized_ = true;
|
||||||
|
SDL_Log("SDL3GPUShader: initialized OK (%dx%d)", tex_width_, tex_height_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// createPipeline
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
auto SDL3GPUShader::createPipeline() -> bool {
|
||||||
|
const SDL_GPUTextureFormat SWAPCHAIN_FMT = SDL_GetGPUSwapchainTextureFormat(device_, window_);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
SDL_GPUShader* vert = createShaderMSL(device_, POSTFX_VERT_MSL, "postfx_vs", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||||
|
SDL_GPUShader* frag = createShaderMSL(device_, POSTFX_FRAG_MSL, "postfx_fs", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
||||||
|
#else
|
||||||
|
SDL_GPUShader* vert = createShaderSPIRV(device_, kpostfx_vert_spv, kpostfx_vert_spv_size, "main", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||||
|
SDL_GPUShader* frag = createShaderSPIRV(device_, kpostfx_frag_spv, kpostfx_frag_spv_size, "main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((vert == nullptr) || (frag == nullptr)) {
|
||||||
|
SDL_Log("SDL3GPUShader: failed to compile PostFX shaders");
|
||||||
|
if (vert != nullptr) { SDL_ReleaseGPUShader(device_, vert); }
|
||||||
|
if (frag != nullptr) { SDL_ReleaseGPUShader(device_, frag); }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUColorTargetBlendState no_blend = {};
|
||||||
|
no_blend.enable_blend = false;
|
||||||
|
no_blend.enable_color_write_mask = false;
|
||||||
|
|
||||||
|
SDL_GPUColorTargetDescription color_target = {};
|
||||||
|
color_target.format = SWAPCHAIN_FMT;
|
||||||
|
color_target.blend_state = no_blend;
|
||||||
|
|
||||||
|
SDL_GPUVertexInputState no_input = {};
|
||||||
|
|
||||||
|
SDL_GPUGraphicsPipelineCreateInfo pipe_info = {};
|
||||||
|
pipe_info.vertex_shader = vert;
|
||||||
|
pipe_info.fragment_shader = frag;
|
||||||
|
pipe_info.vertex_input_state = no_input;
|
||||||
|
pipe_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
||||||
|
pipe_info.target_info.num_color_targets = 1;
|
||||||
|
pipe_info.target_info.color_target_descriptions = &color_target;
|
||||||
|
|
||||||
|
pipeline_ = SDL_CreateGPUGraphicsPipeline(device_, &pipe_info);
|
||||||
|
|
||||||
|
SDL_ReleaseGPUShader(device_, vert);
|
||||||
|
SDL_ReleaseGPUShader(device_, frag);
|
||||||
|
|
||||||
|
if (pipeline_ == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: pipeline creation failed: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// uploadPixels — copies ARGB8888 CPU pixels into the GPU transfer buffer
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
void SDL3GPUShader::uploadPixels(const Uint32* pixels, int width, int height) {
|
||||||
|
if (!is_initialized_ || (upload_buffer_ == nullptr)) { return; }
|
||||||
|
|
||||||
|
void* mapped = SDL_MapGPUTransferBuffer(device_, upload_buffer_, false);
|
||||||
|
if (mapped == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: SDL_MapGPUTransferBuffer failed: %s", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4));
|
||||||
|
SDL_UnmapGPUTransferBuffer(device_, upload_buffer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// render — upload scene texture + PostFX pass → swapchain
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
void SDL3GPUShader::render() {
|
||||||
|
if (!is_initialized_) { return; }
|
||||||
|
|
||||||
|
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_);
|
||||||
|
if (cmd == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Copy pass: transfer buffer → scene texture ----
|
||||||
|
SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);
|
||||||
|
if (copy != nullptr) {
|
||||||
|
SDL_GPUTextureTransferInfo src = {};
|
||||||
|
src.transfer_buffer = upload_buffer_;
|
||||||
|
src.offset = 0;
|
||||||
|
src.pixels_per_row = static_cast<Uint32>(tex_width_);
|
||||||
|
src.rows_per_layer = static_cast<Uint32>(tex_height_);
|
||||||
|
|
||||||
|
SDL_GPUTextureRegion dst = {};
|
||||||
|
dst.texture = scene_texture_;
|
||||||
|
dst.w = static_cast<Uint32>(tex_width_);
|
||||||
|
dst.h = static_cast<Uint32>(tex_height_);
|
||||||
|
dst.d = 1;
|
||||||
|
|
||||||
|
SDL_UploadToGPUTexture(copy, &src, &dst, false);
|
||||||
|
SDL_EndGPUCopyPass(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Acquire swapchain texture ----
|
||||||
|
SDL_GPUTexture* swapchain = nullptr;
|
||||||
|
Uint32 sw = 0;
|
||||||
|
Uint32 sh = 0;
|
||||||
|
if (!SDL_AcquireGPUSwapchainTexture(cmd, window_, &swapchain, &sw, &sh)) {
|
||||||
|
SDL_Log("SDL3GPUShader: SDL_AcquireGPUSwapchainTexture failed: %s", SDL_GetError());
|
||||||
|
SDL_SubmitGPUCommandBuffer(cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (swapchain == nullptr) {
|
||||||
|
// Window minimized — skip frame
|
||||||
|
SDL_SubmitGPUCommandBuffer(cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Render pass: PostFX → swapchain ----
|
||||||
|
SDL_GPUColorTargetInfo color_target = {};
|
||||||
|
color_target.texture = swapchain;
|
||||||
|
color_target.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
color_target.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
color_target.clear_color = {.r = 0.0F, .g = 0.0F, .b = 0.0F, .a = 1.0F};
|
||||||
|
|
||||||
|
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &color_target, 1, nullptr);
|
||||||
|
if (pass != nullptr) {
|
||||||
|
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
||||||
|
|
||||||
|
// Calcular viewport para mantener relación de aspecto (letterbox o integer scale)
|
||||||
|
float vx = 0.0F;
|
||||||
|
float vy = 0.0F;
|
||||||
|
float vw = 0.0F;
|
||||||
|
float vh = 0.0F;
|
||||||
|
if (integer_scale_) {
|
||||||
|
const int SCALE = std::max(1, std::min(static_cast<int>(sw) / tex_width_, static_cast<int>(sh) / tex_height_));
|
||||||
|
vw = static_cast<float>(tex_width_ * SCALE);
|
||||||
|
vh = static_cast<float>(tex_height_ * SCALE);
|
||||||
|
} else {
|
||||||
|
const float SCALE = std::min(
|
||||||
|
static_cast<float>(sw) / static_cast<float>(tex_width_),
|
||||||
|
static_cast<float>(sh) / static_cast<float>(tex_height_));
|
||||||
|
vw = static_cast<float>(tex_width_) * SCALE;
|
||||||
|
vh = static_cast<float>(tex_height_) * SCALE;
|
||||||
|
}
|
||||||
|
vx = std::floor((static_cast<float>(sw) - vw) * 0.5F);
|
||||||
|
vy = std::floor((static_cast<float>(sh) - vh) * 0.5F);
|
||||||
|
SDL_GPUViewport vp = {vx, vy, vw, vh, 0.0F, 1.0F};
|
||||||
|
SDL_SetGPUViewport(pass, &vp);
|
||||||
|
|
||||||
|
SDL_GPUTextureSamplerBinding binding = {};
|
||||||
|
binding.texture = scene_texture_;
|
||||||
|
binding.sampler = sampler_;
|
||||||
|
SDL_BindGPUFragmentSamplers(pass, 0, &binding, 1);
|
||||||
|
|
||||||
|
SDL_PushGPUFragmentUniformData(cmd, 0, &uniforms_, sizeof(PostFXUniforms));
|
||||||
|
|
||||||
|
SDL_DrawGPUPrimitives(pass, 3, 1, 0, 0);
|
||||||
|
SDL_EndGPURenderPass(pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SubmitGPUCommandBuffer(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// cleanup — libera pipeline/texturas/buffer pero mantiene device + swapchain
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
void SDL3GPUShader::cleanup() {
|
||||||
|
is_initialized_ = false;
|
||||||
|
|
||||||
|
if (device_ != nullptr) {
|
||||||
|
SDL_WaitForGPUIdle(device_);
|
||||||
|
|
||||||
|
if (pipeline_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(device_, pipeline_);
|
||||||
|
pipeline_ = nullptr;
|
||||||
|
}
|
||||||
|
if (scene_texture_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUTexture(device_, scene_texture_);
|
||||||
|
scene_texture_ = nullptr;
|
||||||
|
}
|
||||||
|
if (upload_buffer_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
|
||||||
|
upload_buffer_ = nullptr;
|
||||||
|
}
|
||||||
|
if (sampler_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUSampler(device_, sampler_);
|
||||||
|
sampler_ = nullptr;
|
||||||
|
}
|
||||||
|
// device_ y el claim de la ventana se mantienen vivos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// destroy — limpieza completa incluyendo device y swapchain (solo al cerrar)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
void SDL3GPUShader::destroy() {
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
if (device_ != nullptr) {
|
||||||
|
if (window_ != nullptr) {
|
||||||
|
SDL_ReleaseWindowFromGPUDevice(device_, window_);
|
||||||
|
}
|
||||||
SDL_DestroyGPUDevice(device_);
|
SDL_DestroyGPUDevice(device_);
|
||||||
device_ = nullptr;
|
device_ = nullptr;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, vsync_ ? SDL_GPU_PRESENTMODE_VSYNC : SDL_GPU_PRESENTMODE_IMMEDIATE);
|
window_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// 3. Create scene texture (upload target + sampler source)
|
// Shader creation helpers
|
||||||
// Format: B8G8R8A8_UNORM matches SDL ARGB8888 byte layout on LE
|
// ---------------------------------------------------------------------------
|
||||||
// ----------------------------------------------------------------
|
auto SDL3GPUShader::createShaderMSL(SDL_GPUDevice* device,
|
||||||
SDL_GPUTextureCreateInfo tex_info = {};
|
const char* msl_source,
|
||||||
tex_info.type = SDL_GPU_TEXTURETYPE_2D;
|
const char* entrypoint,
|
||||||
tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
|
SDL_GPUShaderStage stage,
|
||||||
tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
Uint32 num_samplers,
|
||||||
tex_info.width = static_cast<Uint32>(tex_width_);
|
Uint32 num_uniform_buffers) -> SDL_GPUShader* {
|
||||||
tex_info.height = static_cast<Uint32>(tex_height_);
|
SDL_GPUShaderCreateInfo info = {};
|
||||||
tex_info.layer_count_or_depth = 1;
|
info.code = reinterpret_cast<const Uint8*>(msl_source);
|
||||||
tex_info.num_levels = 1;
|
info.code_size = std::strlen(msl_source) + 1;
|
||||||
scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info);
|
info.entrypoint = entrypoint;
|
||||||
if (scene_texture_ == nullptr) {
|
info.format = SDL_GPU_SHADERFORMAT_MSL;
|
||||||
SDL_Log("SDL3GPUShader: failed to create scene texture: %s", SDL_GetError());
|
info.stage = stage;
|
||||||
cleanup();
|
info.num_samplers = num_samplers;
|
||||||
return false;
|
info.num_uniform_buffers = num_uniform_buffers;
|
||||||
}
|
SDL_GPUShader* shader = SDL_CreateGPUShader(device, &info);
|
||||||
|
if (shader == nullptr) {
|
||||||
// ----------------------------------------------------------------
|
SDL_Log("SDL3GPUShader: MSL shader '%s' failed: %s", entrypoint, SDL_GetError());
|
||||||
// 4. Create upload transfer buffer (CPU → GPU, size = w*h*4 bytes)
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
SDL_GPUTransferBufferCreateInfo tb_info = {};
|
|
||||||
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
|
||||||
tb_info.size = static_cast<Uint32>(tex_width_ * tex_height_ * 4);
|
|
||||||
upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info);
|
|
||||||
if (upload_buffer_ == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: failed to create upload buffer: %s", SDL_GetError());
|
|
||||||
cleanup();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
// 5. Create nearest-neighbour sampler (retro pixel art)
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
SDL_GPUSamplerCreateInfo samp_info = {};
|
|
||||||
samp_info.min_filter = SDL_GPU_FILTER_NEAREST;
|
|
||||||
samp_info.mag_filter = SDL_GPU_FILTER_NEAREST;
|
|
||||||
samp_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
|
||||||
samp_info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
|
||||||
samp_info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
|
||||||
samp_info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
|
||||||
sampler_ = SDL_CreateGPUSampler(device_, &samp_info);
|
|
||||||
if (sampler_ == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: failed to create sampler: %s", SDL_GetError());
|
|
||||||
cleanup();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
// 6. Create PostFX graphics pipeline
|
|
||||||
// ----------------------------------------------------------------
|
|
||||||
if (!createPipeline()) {
|
|
||||||
cleanup();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_initialized_ = true;
|
|
||||||
SDL_Log("SDL3GPUShader: initialized OK (%dx%d)", tex_width_, tex_height_);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// createPipeline
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
auto SDL3GPUShader::createPipeline() -> bool {
|
|
||||||
const SDL_GPUTextureFormat SWAPCHAIN_FMT = SDL_GetGPUSwapchainTextureFormat(device_, window_);
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
SDL_GPUShader* vert = createShaderMSL(device_, POSTFX_VERT_MSL, "postfx_vs", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
|
||||||
SDL_GPUShader* frag = createShaderMSL(device_, POSTFX_FRAG_MSL, "postfx_fs", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
|
||||||
#else
|
|
||||||
SDL_GPUShader* vert = createShaderSPIRV(device_, kpostfx_vert_spv, kpostfx_vert_spv_size, "main", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
|
||||||
SDL_GPUShader* frag = createShaderSPIRV(device_, kpostfx_frag_spv, kpostfx_frag_spv_size, "main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((vert == nullptr) || (frag == nullptr)) {
|
|
||||||
SDL_Log("SDL3GPUShader: failed to compile PostFX shaders");
|
|
||||||
if (vert != nullptr) { SDL_ReleaseGPUShader(device_, vert); }
|
|
||||||
if (frag != nullptr) { SDL_ReleaseGPUShader(device_, frag); }
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_GPUColorTargetBlendState no_blend = {};
|
|
||||||
no_blend.enable_blend = false;
|
|
||||||
no_blend.enable_color_write_mask = false;
|
|
||||||
|
|
||||||
SDL_GPUColorTargetDescription color_target = {};
|
|
||||||
color_target.format = SWAPCHAIN_FMT;
|
|
||||||
color_target.blend_state = no_blend;
|
|
||||||
|
|
||||||
SDL_GPUVertexInputState no_input = {};
|
|
||||||
|
|
||||||
SDL_GPUGraphicsPipelineCreateInfo pipe_info = {};
|
|
||||||
pipe_info.vertex_shader = vert;
|
|
||||||
pipe_info.fragment_shader = frag;
|
|
||||||
pipe_info.vertex_input_state = no_input;
|
|
||||||
pipe_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
|
||||||
pipe_info.target_info.num_color_targets = 1;
|
|
||||||
pipe_info.target_info.color_target_descriptions = &color_target;
|
|
||||||
|
|
||||||
pipeline_ = SDL_CreateGPUGraphicsPipeline(device_, &pipe_info);
|
|
||||||
|
|
||||||
SDL_ReleaseGPUShader(device_, vert);
|
|
||||||
SDL_ReleaseGPUShader(device_, frag);
|
|
||||||
|
|
||||||
if (pipeline_ == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: pipeline creation failed: %s", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// uploadPixels — copies ARGB8888 CPU pixels into the GPU transfer buffer
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
void SDL3GPUShader::uploadPixels(const Uint32* pixels, int width, int height) {
|
|
||||||
if (!is_initialized_ || (upload_buffer_ == nullptr)) { return; }
|
|
||||||
|
|
||||||
void* mapped = SDL_MapGPUTransferBuffer(device_, upload_buffer_, false);
|
|
||||||
if (mapped == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: SDL_MapGPUTransferBuffer failed: %s", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4));
|
|
||||||
SDL_UnmapGPUTransferBuffer(device_, upload_buffer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// render — upload scene texture + PostFX pass → swapchain
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
void SDL3GPUShader::render() {
|
|
||||||
if (!is_initialized_) { return; }
|
|
||||||
|
|
||||||
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_);
|
|
||||||
if (cmd == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Copy pass: transfer buffer → scene texture ----
|
|
||||||
SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);
|
|
||||||
if (copy != nullptr) {
|
|
||||||
SDL_GPUTextureTransferInfo src = {};
|
|
||||||
src.transfer_buffer = upload_buffer_;
|
|
||||||
src.offset = 0;
|
|
||||||
src.pixels_per_row = static_cast<Uint32>(tex_width_);
|
|
||||||
src.rows_per_layer = static_cast<Uint32>(tex_height_);
|
|
||||||
|
|
||||||
SDL_GPUTextureRegion dst = {};
|
|
||||||
dst.texture = scene_texture_;
|
|
||||||
dst.w = static_cast<Uint32>(tex_width_);
|
|
||||||
dst.h = static_cast<Uint32>(tex_height_);
|
|
||||||
dst.d = 1;
|
|
||||||
|
|
||||||
SDL_UploadToGPUTexture(copy, &src, &dst, false);
|
|
||||||
SDL_EndGPUCopyPass(copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Acquire swapchain texture ----
|
|
||||||
SDL_GPUTexture* swapchain = nullptr;
|
|
||||||
Uint32 sw = 0;
|
|
||||||
Uint32 sh = 0;
|
|
||||||
if (!SDL_AcquireGPUSwapchainTexture(cmd, window_, &swapchain, &sw, &sh)) {
|
|
||||||
SDL_Log("SDL3GPUShader: SDL_AcquireGPUSwapchainTexture failed: %s", SDL_GetError());
|
|
||||||
SDL_SubmitGPUCommandBuffer(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (swapchain == nullptr) {
|
|
||||||
// Window minimized — skip frame
|
|
||||||
SDL_SubmitGPUCommandBuffer(cmd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Render pass: PostFX → swapchain ----
|
|
||||||
SDL_GPUColorTargetInfo color_target = {};
|
|
||||||
color_target.texture = swapchain;
|
|
||||||
color_target.load_op = SDL_GPU_LOADOP_CLEAR;
|
|
||||||
color_target.store_op = SDL_GPU_STOREOP_STORE;
|
|
||||||
color_target.clear_color = {.r = 0.0F, .g = 0.0F, .b = 0.0F, .a = 1.0F};
|
|
||||||
|
|
||||||
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &color_target, 1, nullptr);
|
|
||||||
if (pass != nullptr) {
|
|
||||||
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
|
||||||
|
|
||||||
// Calcular viewport para mantener relación de aspecto (letterbox o integer scale)
|
|
||||||
float vx = 0.0F;
|
|
||||||
float vy = 0.0F;
|
|
||||||
float vw = 0.0F;
|
|
||||||
float vh = 0.0F;
|
|
||||||
if (integer_scale_) {
|
|
||||||
const int SCALE = std::max(1, std::min(static_cast<int>(sw) / tex_width_, static_cast<int>(sh) / tex_height_));
|
|
||||||
vw = static_cast<float>(tex_width_ * SCALE);
|
|
||||||
vh = static_cast<float>(tex_height_ * SCALE);
|
|
||||||
} else {
|
|
||||||
const float SCALE = std::min(
|
|
||||||
static_cast<float>(sw) / static_cast<float>(tex_width_),
|
|
||||||
static_cast<float>(sh) / static_cast<float>(tex_height_));
|
|
||||||
vw = static_cast<float>(tex_width_) * SCALE;
|
|
||||||
vh = static_cast<float>(tex_height_) * SCALE;
|
|
||||||
}
|
}
|
||||||
vx = std::floor((static_cast<float>(sw) - vw) * 0.5F);
|
return shader;
|
||||||
vy = std::floor((static_cast<float>(sh) - vh) * 0.5F);
|
|
||||||
SDL_GPUViewport vp = {vx, vy, vw, vh, 0.0F, 1.0F};
|
|
||||||
SDL_SetGPUViewport(pass, &vp);
|
|
||||||
|
|
||||||
SDL_GPUTextureSamplerBinding binding = {};
|
|
||||||
binding.texture = scene_texture_;
|
|
||||||
binding.sampler = sampler_;
|
|
||||||
SDL_BindGPUFragmentSamplers(pass, 0, &binding, 1);
|
|
||||||
|
|
||||||
SDL_PushGPUFragmentUniformData(cmd, 0, &uniforms_, sizeof(PostFXUniforms));
|
|
||||||
|
|
||||||
SDL_DrawGPUPrimitives(pass, 3, 1, 0, 0);
|
|
||||||
SDL_EndGPURenderPass(pass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SubmitGPUCommandBuffer(cmd);
|
auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device,
|
||||||
}
|
const uint8_t* spv_code,
|
||||||
|
size_t spv_size,
|
||||||
// ---------------------------------------------------------------------------
|
const char* entrypoint,
|
||||||
// cleanup — libera pipeline/texturas/buffer pero mantiene device + swapchain
|
SDL_GPUShaderStage stage,
|
||||||
// ---------------------------------------------------------------------------
|
Uint32 num_samplers,
|
||||||
void SDL3GPUShader::cleanup() {
|
Uint32 num_uniform_buffers) -> SDL_GPUShader* {
|
||||||
is_initialized_ = false;
|
SDL_GPUShaderCreateInfo info = {};
|
||||||
|
info.code = spv_code;
|
||||||
if (device_ != nullptr) {
|
info.code_size = spv_size;
|
||||||
SDL_WaitForGPUIdle(device_);
|
info.entrypoint = entrypoint;
|
||||||
|
info.format = SDL_GPU_SHADERFORMAT_SPIRV;
|
||||||
if (pipeline_ != nullptr) {
|
info.stage = stage;
|
||||||
SDL_ReleaseGPUGraphicsPipeline(device_, pipeline_);
|
info.num_samplers = num_samplers;
|
||||||
pipeline_ = nullptr;
|
info.num_uniform_buffers = num_uniform_buffers;
|
||||||
|
SDL_GPUShader* shader = SDL_CreateGPUShader(device, &info);
|
||||||
|
if (shader == nullptr) {
|
||||||
|
SDL_Log("SDL3GPUShader: SPIRV shader '%s' failed: %s", entrypoint, SDL_GetError());
|
||||||
}
|
}
|
||||||
if (scene_texture_ != nullptr) {
|
return shader;
|
||||||
SDL_ReleaseGPUTexture(device_, scene_texture_);
|
}
|
||||||
scene_texture_ = nullptr;
|
|
||||||
|
void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
|
||||||
|
uniforms_.vignette_strength = p.vignette;
|
||||||
|
uniforms_.scanline_strength = p.scanlines;
|
||||||
|
uniforms_.chroma_strength = p.chroma;
|
||||||
|
uniforms_.mask_strength = p.mask;
|
||||||
|
uniforms_.gamma_strength = p.gamma;
|
||||||
|
uniforms_.curvature = p.curvature;
|
||||||
|
uniforms_.bleeding = p.bleeding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDL3GPUShader::setVSync(bool vsync) {
|
||||||
|
vsync_ = vsync;
|
||||||
|
if (device_ != nullptr && window_ != nullptr) {
|
||||||
|
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, vsync_ ? SDL_GPU_PRESENTMODE_VSYNC : SDL_GPU_PRESENTMODE_IMMEDIATE);
|
||||||
}
|
}
|
||||||
if (upload_buffer_ != nullptr) {
|
|
||||||
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
|
|
||||||
upload_buffer_ = nullptr;
|
|
||||||
}
|
|
||||||
if (sampler_ != nullptr) {
|
|
||||||
SDL_ReleaseGPUSampler(device_, sampler_);
|
|
||||||
sampler_ = nullptr;
|
|
||||||
}
|
|
||||||
// device_ y el claim de la ventana se mantienen vivos
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
void SDL3GPUShader::setScaleMode(bool integer_scale) {
|
||||||
// destroy — limpieza completa incluyendo device y swapchain (solo al cerrar)
|
integer_scale_ = integer_scale;
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
void SDL3GPUShader::destroy() {
|
|
||||||
cleanup();
|
|
||||||
|
|
||||||
if (device_ != nullptr) {
|
|
||||||
if (window_ != nullptr) {
|
|
||||||
SDL_ReleaseWindowFromGPUDevice(device_, window_);
|
|
||||||
}
|
|
||||||
SDL_DestroyGPUDevice(device_);
|
|
||||||
device_ = nullptr;
|
|
||||||
}
|
}
|
||||||
window_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Shader creation helpers
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
auto SDL3GPUShader::createShaderMSL(SDL_GPUDevice* device,
|
|
||||||
const char* msl_source,
|
|
||||||
const char* entrypoint,
|
|
||||||
SDL_GPUShaderStage stage,
|
|
||||||
Uint32 num_samplers,
|
|
||||||
Uint32 num_uniform_buffers) -> SDL_GPUShader* {
|
|
||||||
SDL_GPUShaderCreateInfo info = {};
|
|
||||||
info.code = reinterpret_cast<const Uint8*>(msl_source);
|
|
||||||
info.code_size = std::strlen(msl_source) + 1;
|
|
||||||
info.entrypoint = entrypoint;
|
|
||||||
info.format = SDL_GPU_SHADERFORMAT_MSL;
|
|
||||||
info.stage = stage;
|
|
||||||
info.num_samplers = num_samplers;
|
|
||||||
info.num_uniform_buffers = num_uniform_buffers;
|
|
||||||
SDL_GPUShader* shader = SDL_CreateGPUShader(device, &info);
|
|
||||||
if (shader == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: MSL shader '%s' failed: %s", entrypoint, SDL_GetError());
|
|
||||||
}
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device,
|
|
||||||
const uint8_t* spv_code,
|
|
||||||
size_t spv_size,
|
|
||||||
const char* entrypoint,
|
|
||||||
SDL_GPUShaderStage stage,
|
|
||||||
Uint32 num_samplers,
|
|
||||||
Uint32 num_uniform_buffers) -> SDL_GPUShader* {
|
|
||||||
SDL_GPUShaderCreateInfo info = {};
|
|
||||||
info.code = spv_code;
|
|
||||||
info.code_size = spv_size;
|
|
||||||
info.entrypoint = entrypoint;
|
|
||||||
info.format = SDL_GPU_SHADERFORMAT_SPIRV;
|
|
||||||
info.stage = stage;
|
|
||||||
info.num_samplers = num_samplers;
|
|
||||||
info.num_uniform_buffers = num_uniform_buffers;
|
|
||||||
SDL_GPUShader* shader = SDL_CreateGPUShader(device, &info);
|
|
||||||
if (shader == nullptr) {
|
|
||||||
SDL_Log("SDL3GPUShader: SPIRV shader '%s' failed: %s", entrypoint, SDL_GetError());
|
|
||||||
}
|
|
||||||
return shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
|
|
||||||
uniforms_.vignette_strength = p.vignette;
|
|
||||||
uniforms_.scanline_strength = p.scanlines;
|
|
||||||
uniforms_.chroma_strength = p.chroma;
|
|
||||||
uniforms_.mask_strength = p.mask;
|
|
||||||
uniforms_.gamma_strength = p.gamma;
|
|
||||||
uniforms_.curvature = p.curvature;
|
|
||||||
uniforms_.bleeding = p.bleeding;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL3GPUShader::setVSync(bool vsync) {
|
|
||||||
vsync_ = vsync;
|
|
||||||
if (device_ != nullptr && window_ != nullptr) {
|
|
||||||
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, vsync_ ? SDL_GPU_PRESENTMODE_VSYNC : SDL_GPU_PRESENTMODE_IMMEDIATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL3GPUShader::setScaleMode(bool integer_scale) {
|
|
||||||
integer_scale_ = integer_scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Rendering
|
} // namespace Rendering
|
||||||
|
|||||||
@@ -9,27 +9,27 @@
|
|||||||
// Must match the MSL struct and GLSL uniform block layout.
|
// Must match the MSL struct and GLSL uniform block layout.
|
||||||
// 8 floats = 32 bytes — meets Metal/Vulkan 16-byte alignment requirement.
|
// 8 floats = 32 bytes — meets Metal/Vulkan 16-byte alignment requirement.
|
||||||
struct PostFXUniforms {
|
struct PostFXUniforms {
|
||||||
float vignette_strength; // 0 = none, ~0.8 = subtle
|
float vignette_strength; // 0 = none, ~0.8 = subtle
|
||||||
float chroma_strength; // 0 = off, ~0.2 = subtle chromatic aberration
|
float chroma_strength; // 0 = off, ~0.2 = subtle chromatic aberration
|
||||||
float scanline_strength; // 0 = off, 1 = full
|
float scanline_strength; // 0 = off, 1 = full
|
||||||
float screen_height; // logical height in pixels (for resolution-independent scanlines)
|
float screen_height; // logical height in pixels (for resolution-independent scanlines)
|
||||||
float mask_strength; // 0 = off, 1 = full phosphor dot mask
|
float mask_strength; // 0 = off, 1 = full phosphor dot mask
|
||||||
float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction
|
float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction
|
||||||
float curvature; // 0 = flat, 1 = max barrel distortion
|
float curvature; // 0 = flat, 1 = max barrel distortion
|
||||||
float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding
|
float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Backend de shaders usando SDL3 GPU API (Metal en macOS, Vulkan/SPIR-V en Win/Linux)
|
* @brief Backend de shaders usando SDL3 GPU API (Metal en macOS, Vulkan/SPIR-V en Win/Linux)
|
||||||
*
|
*
|
||||||
* Reemplaza el backend OpenGL para que los shaders PostFX funcionen en macOS.
|
* Reemplaza el backend OpenGL para que los shaders PostFX funcionen en macOS.
|
||||||
* Pipeline: Surface pixels (CPU) → SDL_GPUTransferBuffer → SDL_GPUTexture (scene)
|
* Pipeline: Surface pixels (CPU) → SDL_GPUTransferBuffer → SDL_GPUTexture (scene)
|
||||||
* → PostFX render pass → swapchain → present
|
* → PostFX render pass → swapchain → present
|
||||||
*/
|
*/
|
||||||
class SDL3GPUShader : public ShaderBackend {
|
class SDL3GPUShader : public ShaderBackend {
|
||||||
public:
|
public:
|
||||||
SDL3GPUShader() = default;
|
SDL3GPUShader() = default;
|
||||||
~SDL3GPUShader() override;
|
~SDL3GPUShader() override;
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ class SDL3GPUShader : public ShaderBackend {
|
|||||||
void render() override;
|
void render() override;
|
||||||
void setTextureSize(float width, float height) override {}
|
void setTextureSize(float width, float height) override {}
|
||||||
void cleanup() final; // Libera pipeline/texturas pero mantiene el device vivo
|
void cleanup() final; // Libera pipeline/texturas pero mantiene el device vivo
|
||||||
void destroy(); // Limpieza completa (device + swapchain); llamar solo al cerrar
|
void destroy(); // Limpieza completa (device + swapchain); llamar solo al cerrar
|
||||||
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
|
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
|
||||||
|
|
||||||
// Sube píxeles ARGB8888 desde CPU; llamado antes de render()
|
// Sube píxeles ARGB8888 desde CPU; llamado antes de render()
|
||||||
@@ -56,7 +56,7 @@ class SDL3GPUShader : public ShaderBackend {
|
|||||||
// Activa/desactiva escalado entero (integer scale)
|
// Activa/desactiva escalado entero (integer scale)
|
||||||
void setScaleMode(bool integer_scale) override;
|
void setScaleMode(bool integer_scale) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static auto createShaderMSL(SDL_GPUDevice* device,
|
static auto createShaderMSL(SDL_GPUDevice* device,
|
||||||
const char* msl_source,
|
const char* msl_source,
|
||||||
const char* entrypoint,
|
const char* entrypoint,
|
||||||
@@ -88,6 +88,6 @@ class SDL3GPUShader : public ShaderBackend {
|
|||||||
bool is_initialized_ = false;
|
bool is_initialized_ = false;
|
||||||
bool vsync_ = true;
|
bool vsync_ = true;
|
||||||
bool integer_scale_ = false;
|
bool integer_scale_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Rendering
|
} // namespace Rendering
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
|
|
||||||
namespace Rendering {
|
namespace Rendering {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parámetros de intensidad de los efectos PostFX
|
* @brief Parámetros de intensidad de los efectos PostFX
|
||||||
* Definido a nivel de namespace para facilitar el uso desde subclases y screen.cpp
|
* Definido a nivel de namespace para facilitar el uso desde subclases y screen.cpp
|
||||||
*/
|
*/
|
||||||
struct PostFXParams {
|
struct PostFXParams {
|
||||||
float vignette = 0.0F; // Intensidad de la viñeta
|
float vignette = 0.0F; // Intensidad de la viñeta
|
||||||
float scanlines = 0.0F; // Intensidad de las scanlines
|
float scanlines = 0.0F; // Intensidad de las scanlines
|
||||||
float chroma = 0.0F; // Aberración cromática
|
float chroma = 0.0F; // Aberración cromática
|
||||||
@@ -18,16 +18,16 @@ struct PostFXParams {
|
|||||||
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
|
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
|
||||||
float curvature = 0.0F; // Curvatura barrel CRT
|
float curvature = 0.0F; // Curvatura barrel CRT
|
||||||
float bleeding = 0.0F; // Sangrado de color NTSC
|
float bleeding = 0.0F; // Sangrado de color NTSC
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Interfaz abstracta para backends de renderizado con shaders
|
* @brief Interfaz abstracta para backends de renderizado con shaders
|
||||||
*
|
*
|
||||||
* Esta interfaz define el contrato que todos los backends de shaders
|
* Esta interfaz define el contrato que todos los backends de shaders
|
||||||
* deben cumplir (OpenGL, Metal, Vulkan, etc.)
|
* deben cumplir (OpenGL, Metal, Vulkan, etc.)
|
||||||
*/
|
*/
|
||||||
class ShaderBackend {
|
class ShaderBackend {
|
||||||
public:
|
public:
|
||||||
virtual ~ShaderBackend() = default;
|
virtual ~ShaderBackend() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,6 +87,6 @@ class ShaderBackend {
|
|||||||
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual auto isHardwareAccelerated() const -> bool = 0;
|
[[nodiscard]] virtual auto isHardwareAccelerated() const -> bool = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Rendering
|
} // namespace Rendering
|
||||||
|
|||||||
@@ -21,129 +21,129 @@ auto loadPalette(const std::string& file_path) -> Palette;
|
|||||||
auto readPalFile(const std::string& file_path) -> Palette;
|
auto readPalFile(const std::string& file_path) -> Palette;
|
||||||
|
|
||||||
struct SurfaceData {
|
struct SurfaceData {
|
||||||
std::shared_ptr<Uint8[]> data; // Usa std::shared_ptr para gestión automática
|
std::shared_ptr<Uint8[]> data; // Usa std::shared_ptr para gestión automática
|
||||||
float width; // Ancho de la imagen
|
float width; // Ancho de la imagen
|
||||||
float height; // Alto de la imagen
|
float height; // Alto de la imagen
|
||||||
|
|
||||||
// Constructor por defecto
|
// Constructor por defecto
|
||||||
SurfaceData()
|
SurfaceData()
|
||||||
: data(nullptr),
|
: data(nullptr),
|
||||||
width(0),
|
width(0),
|
||||||
height(0) {}
|
height(0) {}
|
||||||
|
|
||||||
// Constructor que inicializa dimensiones y asigna memoria
|
// Constructor que inicializa dimensiones y asigna memoria
|
||||||
SurfaceData(float w, float h)
|
SurfaceData(float w, float h)
|
||||||
: data(std::shared_ptr<Uint8[]>(new Uint8[static_cast<size_t>(w * h)](), std::default_delete<Uint8[]>())),
|
: data(std::shared_ptr<Uint8[]>(new Uint8[static_cast<size_t>(w * h)](), std::default_delete<Uint8[]>())),
|
||||||
width(w),
|
width(w),
|
||||||
height(h) {}
|
height(h) {}
|
||||||
|
|
||||||
// Constructor para inicializar directamente con datos
|
// Constructor para inicializar directamente con datos
|
||||||
SurfaceData(float w, float h, std::shared_ptr<Uint8[]> pixels)
|
SurfaceData(float w, float h, std::shared_ptr<Uint8[]> pixels)
|
||||||
: data(std::move(pixels)),
|
: data(std::move(pixels)),
|
||||||
width(w),
|
width(w),
|
||||||
height(h) {}
|
height(h) {}
|
||||||
|
|
||||||
// Constructor de movimiento
|
// Constructor de movimiento
|
||||||
SurfaceData(SurfaceData&& other) noexcept = default;
|
SurfaceData(SurfaceData&& other) noexcept = default;
|
||||||
|
|
||||||
// Operador de movimiento
|
// Operador de movimiento
|
||||||
auto operator=(SurfaceData&& other) noexcept -> SurfaceData& = default;
|
auto operator=(SurfaceData&& other) noexcept -> SurfaceData& = default;
|
||||||
|
|
||||||
// Evita copias accidentales
|
// Evita copias accidentales
|
||||||
SurfaceData(const SurfaceData&) = delete;
|
SurfaceData(const SurfaceData&) = delete;
|
||||||
auto operator=(const SurfaceData&) -> SurfaceData& = delete;
|
auto operator=(const SurfaceData&) -> SurfaceData& = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Surface {
|
class Surface {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<SurfaceData> surface_data_; // Datos a dibujar
|
std::shared_ptr<SurfaceData> surface_data_; // Datos a dibujar
|
||||||
Palette palette_; // Paleta para volcar la SurfaceData a una Textura
|
Palette palette_; // Paleta para volcar la SurfaceData a una Textura
|
||||||
SubPalette sub_palette_; // Paleta para reindexar colores
|
SubPalette sub_palette_; // Paleta para reindexar colores
|
||||||
int transparent_color_; // Indice de la paleta que se omite en la copia de datos
|
int transparent_color_; // Indice de la paleta que se omite en la copia de datos
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Surface(int w, int h);
|
Surface(int w, int h);
|
||||||
explicit Surface(const std::string& file_path);
|
explicit Surface(const std::string& file_path);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Surface() = default;
|
~Surface() = default;
|
||||||
|
|
||||||
// Carga una SurfaceData desde un archivo
|
// Carga una SurfaceData desde un archivo
|
||||||
static auto loadSurface(const std::string& file_path) -> SurfaceData;
|
static auto loadSurface(const std::string& file_path) -> SurfaceData;
|
||||||
|
|
||||||
// Carga una paleta desde un archivo
|
// Carga una paleta desde un archivo
|
||||||
void loadPalette(const std::string& file_path);
|
void loadPalette(const std::string& file_path);
|
||||||
void loadPalette(const Palette& palette);
|
void loadPalette(const Palette& palette);
|
||||||
|
|
||||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino
|
// Copia una región de la SurfaceData de origen a la SurfaceData de destino
|
||||||
void render(float dx, float dy, float sx, float sy, float w, float h);
|
void render(float dx, float dy, float sx, float sy, float w, float h);
|
||||||
void render(int x, int y, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
void render(int x, int y, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
||||||
void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
||||||
|
|
||||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
||||||
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
|
||||||
|
|
||||||
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
|
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
|
||||||
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect = nullptr);
|
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect = nullptr);
|
||||||
|
|
||||||
// Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color)
|
// Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color)
|
||||||
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect = nullptr);
|
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect = nullptr);
|
||||||
|
|
||||||
// Establece un color en la paleta
|
// Establece un color en la paleta
|
||||||
void setColor(int index, Uint32 color);
|
void setColor(int index, Uint32 color);
|
||||||
|
|
||||||
// Rellena la SurfaceData con un color
|
// Rellena la SurfaceData con un color
|
||||||
void clear(Uint8 color);
|
void clear(Uint8 color);
|
||||||
|
|
||||||
// Vuelca la SurfaceData a una textura
|
// Vuelca la SurfaceData a una textura
|
||||||
void copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture);
|
void copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture);
|
||||||
void copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect);
|
void copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect);
|
||||||
|
|
||||||
// Realiza un efecto de fundido en las paletas
|
// Realiza un efecto de fundido en las paletas
|
||||||
auto fadePalette() -> bool;
|
auto fadePalette() -> bool;
|
||||||
auto fadeSubPalette(Uint32 delay = 0) -> bool;
|
auto fadeSubPalette(Uint32 delay = 0) -> bool;
|
||||||
|
|
||||||
// Vuelca los píxeles como ARGB8888 a un buffer externo (sin SDL_Texture)
|
// Vuelca los píxeles como ARGB8888 a un buffer externo (sin SDL_Texture)
|
||||||
void toARGBBuffer(Uint32* buffer) const;
|
void toARGBBuffer(Uint32* buffer) const;
|
||||||
|
|
||||||
// Pone un pixel en la SurfaceData
|
// Pone un pixel en la SurfaceData
|
||||||
void putPixel(int x, int y, Uint8 color);
|
void putPixel(int x, int y, Uint8 color);
|
||||||
|
|
||||||
// Obtiene el color de un pixel de la surface_data
|
// Obtiene el color de un pixel de la surface_data
|
||||||
auto getPixel(int x, int y) -> Uint8;
|
auto getPixel(int x, int y) -> Uint8;
|
||||||
|
|
||||||
// Dibuja un rectangulo relleno
|
// Dibuja un rectangulo relleno
|
||||||
void fillRect(const SDL_FRect* rect, Uint8 color);
|
void fillRect(const SDL_FRect* rect, Uint8 color);
|
||||||
|
|
||||||
// Dibuja el borde de un rectangulo
|
// Dibuja el borde de un rectangulo
|
||||||
void drawRectBorder(const SDL_FRect* rect, Uint8 color);
|
void drawRectBorder(const SDL_FRect* rect, Uint8 color);
|
||||||
|
|
||||||
// Dibuja una linea
|
// Dibuja una linea
|
||||||
void drawLine(float x1, float y1, float x2, float y2, Uint8 color);
|
void drawLine(float x1, float y1, float x2, float y2, Uint8 color);
|
||||||
|
|
||||||
// Metodos para gestionar surface_data_
|
// Metodos para gestionar surface_data_
|
||||||
[[nodiscard]] auto getSurfaceData() const -> std::shared_ptr<SurfaceData> { return surface_data_; }
|
[[nodiscard]] auto getSurfaceData() const -> std::shared_ptr<SurfaceData> { return surface_data_; }
|
||||||
void setSurfaceData(std::shared_ptr<SurfaceData> new_data) { surface_data_ = std::move(new_data); }
|
void setSurfaceData(std::shared_ptr<SurfaceData> new_data) { surface_data_ = std::move(new_data); }
|
||||||
|
|
||||||
// Obtien ancho y alto
|
// Obtien ancho y alto
|
||||||
[[nodiscard]] auto getWidth() const -> float { return surface_data_->width; }
|
[[nodiscard]] auto getWidth() const -> float { return surface_data_->width; }
|
||||||
[[nodiscard]] auto getHeight() const -> float { return surface_data_->height; }
|
[[nodiscard]] auto getHeight() const -> float { return surface_data_->height; }
|
||||||
|
|
||||||
// Color transparente
|
// Color transparente
|
||||||
[[nodiscard]] auto getTransparentColor() const -> Uint8 { return transparent_color_; }
|
[[nodiscard]] auto getTransparentColor() const -> Uint8 { return transparent_color_; }
|
||||||
void setTransparentColor(Uint8 color = 255) { transparent_color_ = color; }
|
void setTransparentColor(Uint8 color = 255) { transparent_color_ = color; }
|
||||||
|
|
||||||
// Paleta
|
// Paleta
|
||||||
void setPalette(const std::array<Uint32, 256>& palette) { palette_ = palette; }
|
void setPalette(const std::array<Uint32, 256>& palette) { palette_ = palette; }
|
||||||
|
|
||||||
// Inicializa la sub paleta
|
// Inicializa la sub paleta
|
||||||
static void initializeSubPalette(SubPalette& palette) { std::iota(palette.begin(), palette.end(), 0); }
|
static void initializeSubPalette(SubPalette& palette) { std::iota(palette.begin(), palette.end(), 0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Helper para calcular coordenadas con flip
|
// Helper para calcular coordenadas con flip
|
||||||
static void calculateFlippedCoords(int ix, int iy, float sx, float sy, float w, float h, SDL_FlipMode flip, int& src_x, int& src_y);
|
static void calculateFlippedCoords(int ix, int iy, float sx, float sy, float w, float h, SDL_FlipMode flip, int& src_x, int& src_y);
|
||||||
|
|
||||||
// Helper para copiar un pixel si no es transparente
|
// Helper para copiar un pixel si no es transparente
|
||||||
void copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const;
|
void copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y, int dest_width, int src_x, int src_y) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,50 +13,50 @@
|
|||||||
class Surface;
|
class Surface;
|
||||||
|
|
||||||
class SurfaceAnimatedSprite : public SurfaceMovingSprite {
|
class SurfaceAnimatedSprite : public SurfaceMovingSprite {
|
||||||
public:
|
public:
|
||||||
using Animations = std::vector<std::string>; // Tipo para lista de animaciones
|
using Animations = std::vector<std::string>; // Tipo para lista de animaciones
|
||||||
|
|
||||||
// Estructura pública de datos de animación
|
// Estructura pública de datos de animación
|
||||||
struct AnimationData {
|
struct AnimationData {
|
||||||
std::string name; // Nombre de la animacion
|
std::string name; // Nombre de la animacion
|
||||||
std::vector<SDL_FRect> frames; // Cada uno de los frames que componen la animación
|
std::vector<SDL_FRect> frames; // Cada uno de los frames que componen la animación
|
||||||
float speed{0.083F}; // Velocidad de la animación (segundos por frame)
|
float speed{0.083F}; // Velocidad de la animación (segundos por frame)
|
||||||
int loop{0}; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
|
int loop{0}; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
|
||||||
bool completed{false}; // Indica si ha finalizado la animación
|
bool completed{false}; // Indica si ha finalizado la animación
|
||||||
int current_frame{0}; // Frame actual
|
int current_frame{0}; // Frame actual
|
||||||
float accumulated_time{0.0F}; // Tiempo acumulado para las animaciones (time-based)
|
float accumulated_time{0.0F}; // Tiempo acumulado para las animaciones (time-based)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Métodos estáticos
|
// Métodos estáticos
|
||||||
static auto loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData>; // Carga las animaciones desde fichero YAML
|
static auto loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData>; // Carga las animaciones desde fichero YAML
|
||||||
|
|
||||||
// Constructores
|
// Constructores
|
||||||
explicit SurfaceAnimatedSprite(const AnimationResource& cached_data); // Constructor con datos pre-cargados del cache
|
explicit SurfaceAnimatedSprite(const AnimationResource& cached_data); // Constructor con datos pre-cargados del cache
|
||||||
|
|
||||||
~SurfaceAnimatedSprite() override = default; // Destructor
|
~SurfaceAnimatedSprite() override = default; // Destructor
|
||||||
|
|
||||||
void update(float delta_time) override; // Actualiza las variables del objeto (time-based)
|
void update(float delta_time) override; // Actualiza las variables del objeto (time-based)
|
||||||
|
|
||||||
// Consultas de estado
|
// Consultas de estado
|
||||||
auto animationIsCompleted() -> bool; // Comprueba si ha terminado la animación
|
auto animationIsCompleted() -> bool; // Comprueba si ha terminado la animación
|
||||||
auto getIndex(const std::string& name) -> int; // Obtiene el índice de la animación por nombre
|
auto getIndex(const std::string& name) -> int; // Obtiene el índice de la animación por nombre
|
||||||
auto getCurrentAnimationSize() -> int { return static_cast<int>(animations_[current_animation_].frames.size()); } // Número de frames de la animación actual
|
auto getCurrentAnimationSize() -> int { return static_cast<int>(animations_[current_animation_].frames.size()); } // Número de frames de la animación actual
|
||||||
|
|
||||||
// Modificadores de animación
|
// Modificadores de animación
|
||||||
void setCurrentAnimation(const std::string& name = "default"); // Establece la animación actual por nombre
|
void setCurrentAnimation(const std::string& name = "default"); // Establece la animación actual por nombre
|
||||||
void setCurrentAnimation(int index = 0); // Establece la animación actual por índice
|
void setCurrentAnimation(int index = 0); // Establece la animación actual por índice
|
||||||
void resetAnimation(); // Reinicia la animación
|
void resetAnimation(); // Reinicia la animación
|
||||||
void setCurrentAnimationFrame(int num); // Establece el frame actual de la animación
|
void setCurrentAnimationFrame(int num); // Establece el frame actual de la animación
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Constructor per a ús de subclasses que gestionen la surface directament (sense YAML)
|
// Constructor per a ús de subclasses que gestionen la surface directament (sense YAML)
|
||||||
SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
|
SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
|
||||||
|
|
||||||
// Métodos protegidos
|
// Métodos protegidos
|
||||||
void animate(float delta_time); // Calcula el frame correspondiente a la animación actual (time-based)
|
void animate(float delta_time); // Calcula el frame correspondiente a la animación actual (time-based)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Variables miembro
|
// Variables miembro
|
||||||
std::vector<AnimationData> animations_; // Vector con las diferentes animaciones
|
std::vector<AnimationData> animations_; // Vector con las diferentes animaciones
|
||||||
int current_animation_{0}; // Animación activa
|
int current_animation_{0}; // Animación activa
|
||||||
};
|
};
|
||||||
@@ -16,47 +16,47 @@ enum class DissolveDirection { NONE,
|
|||||||
// Sprite que pot dissoldre's o generar-se de forma aleatòria en X mil·lisegons.
|
// Sprite que pot dissoldre's o generar-se de forma aleatòria en X mil·lisegons.
|
||||||
// progress_ va de 0.0 (totalment visible) a 1.0 (totalment invisible).
|
// progress_ va de 0.0 (totalment visible) a 1.0 (totalment invisible).
|
||||||
class SurfaceDissolveSprite : public SurfaceAnimatedSprite {
|
class SurfaceDissolveSprite : public SurfaceAnimatedSprite {
|
||||||
public:
|
public:
|
||||||
explicit SurfaceDissolveSprite(const AnimationResource& data);
|
explicit SurfaceDissolveSprite(const AnimationResource& data);
|
||||||
SurfaceDissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
|
SurfaceDissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
|
||||||
~SurfaceDissolveSprite() override = default;
|
~SurfaceDissolveSprite() override = default;
|
||||||
|
|
||||||
void update(float delta_time) override;
|
void update(float delta_time) override;
|
||||||
void render() override;
|
void render() override;
|
||||||
|
|
||||||
// Progrés manual [0.0 = totalment visible, 1.0 = totalment invisible]
|
// Progrés manual [0.0 = totalment visible, 1.0 = totalment invisible]
|
||||||
void setProgress(float progress);
|
void setProgress(float progress);
|
||||||
[[nodiscard]] auto getProgress() const -> float { return progress_; }
|
[[nodiscard]] auto getProgress() const -> float { return progress_; }
|
||||||
|
|
||||||
// Inicia una dissolució temporal (visible → invisible en duration_ms)
|
// Inicia una dissolució temporal (visible → invisible en duration_ms)
|
||||||
void startDissolve(float duration_ms, DissolveDirection dir = DissolveDirection::NONE);
|
void startDissolve(float duration_ms, DissolveDirection dir = DissolveDirection::NONE);
|
||||||
|
|
||||||
// Inicia una generació temporal (invisible → visible en duration_ms)
|
// Inicia una generació temporal (invisible → visible en duration_ms)
|
||||||
void startGenerate(float duration_ms, DissolveDirection dir = DissolveDirection::NONE);
|
void startGenerate(float duration_ms, DissolveDirection dir = DissolveDirection::NONE);
|
||||||
|
|
||||||
void stopTransition();
|
void stopTransition();
|
||||||
[[nodiscard]] auto isTransitionDone() const -> bool;
|
[[nodiscard]] auto isTransitionDone() const -> bool;
|
||||||
|
|
||||||
// Substitució de color: en reconstruir, substitueix source per target
|
// Substitució de color: en reconstruir, substitueix source per target
|
||||||
void setColorReplace(Uint8 source, Uint8 target);
|
void setColorReplace(Uint8 source, Uint8 target);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class TransitionMode { NONE,
|
enum class TransitionMode { NONE,
|
||||||
DISSOLVING,
|
DISSOLVING,
|
||||||
GENERATING };
|
GENERATING };
|
||||||
|
|
||||||
std::shared_ptr<Surface> surface_display_; // Superfície amb els píxels filtrats
|
std::shared_ptr<Surface> surface_display_; // Superfície amb els píxels filtrats
|
||||||
|
|
||||||
float progress_{0.0F}; // [0=visible, 1=invisible]
|
float progress_{0.0F}; // [0=visible, 1=invisible]
|
||||||
DissolveDirection direction_{DissolveDirection::NONE};
|
DissolveDirection direction_{DissolveDirection::NONE};
|
||||||
TransitionMode transition_mode_{TransitionMode::NONE};
|
TransitionMode transition_mode_{TransitionMode::NONE};
|
||||||
float transition_duration_{0.0F};
|
float transition_duration_{0.0F};
|
||||||
float transition_elapsed_{0.0F};
|
float transition_elapsed_{0.0F};
|
||||||
SDL_FRect prev_clip_{0, 0, 0, 0};
|
SDL_FRect prev_clip_{0, 0, 0, 0};
|
||||||
bool needs_rebuild_{false};
|
bool needs_rebuild_{false};
|
||||||
Uint8 source_color_{255}; // 255 = transparent = sense replace per defecte
|
Uint8 source_color_{255}; // 255 = transparent = sense replace per defecte
|
||||||
Uint8 target_color_{0};
|
Uint8 target_color_{0};
|
||||||
|
|
||||||
void rebuildDisplaySurface();
|
void rebuildDisplaySurface();
|
||||||
[[nodiscard]] static auto computePixelRank(int col, int row, int frame_h, DissolveDirection dir) -> float;
|
[[nodiscard]] static auto computePixelRank(int col, int row, int frame_h, DissolveDirection dir) -> float;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,69 +9,69 @@ class Surface; // lines 8-8
|
|||||||
|
|
||||||
// Clase SMovingSprite. Añade movimiento y flip al sprite
|
// Clase SMovingSprite. Añade movimiento y flip al sprite
|
||||||
class SurfaceMovingSprite : public SurfaceSprite {
|
class SurfaceMovingSprite : public SurfaceSprite {
|
||||||
public:
|
public:
|
||||||
// Constructores
|
// Constructores
|
||||||
SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip);
|
SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip);
|
||||||
SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
|
SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
|
||||||
explicit SurfaceMovingSprite();
|
explicit SurfaceMovingSprite();
|
||||||
explicit SurfaceMovingSprite(std::shared_ptr<Surface> surface);
|
explicit SurfaceMovingSprite(std::shared_ptr<Surface> surface);
|
||||||
~SurfaceMovingSprite() override = default;
|
~SurfaceMovingSprite() override = default;
|
||||||
|
|
||||||
// Actualización y renderizado
|
// Actualización y renderizado
|
||||||
void update(float delta_time) override; // Actualiza variables internas (time-based)
|
void update(float delta_time) override; // Actualiza variables internas (time-based)
|
||||||
void render() override; // Muestra el sprite por pantalla
|
void render() override; // Muestra el sprite por pantalla
|
||||||
void render(Uint8 source_color, Uint8 target_color) override; // Renderiza con reemplazo de color
|
void render(Uint8 source_color, Uint8 target_color) override; // Renderiza con reemplazo de color
|
||||||
|
|
||||||
// Gestión de estado
|
// Gestión de estado
|
||||||
void clear() override; // Reinicia todas las variables a cero
|
void clear() override; // Reinicia todas las variables a cero
|
||||||
|
|
||||||
// Getters de posición
|
// Getters de posición
|
||||||
[[nodiscard]] auto getPosX() const -> float { return x_; }
|
[[nodiscard]] auto getPosX() const -> float { return x_; }
|
||||||
[[nodiscard]] auto getPosY() const -> float { return y_; }
|
[[nodiscard]] auto getPosY() const -> float { return y_; }
|
||||||
|
|
||||||
// Getters de velocidad
|
// Getters de velocidad
|
||||||
[[nodiscard]] auto getVelX() const -> float { return vx_; }
|
[[nodiscard]] auto getVelX() const -> float { return vx_; }
|
||||||
[[nodiscard]] auto getVelY() const -> float { return vy_; }
|
[[nodiscard]] auto getVelY() const -> float { return vy_; }
|
||||||
|
|
||||||
// Getters de aceleración
|
// Getters de aceleración
|
||||||
[[nodiscard]] auto getAccelX() const -> float { return ax_; }
|
[[nodiscard]] auto getAccelX() const -> float { return ax_; }
|
||||||
[[nodiscard]] auto getAccelY() const -> float { return ay_; }
|
[[nodiscard]] auto getAccelY() const -> float { return ay_; }
|
||||||
|
|
||||||
// Setters de posición
|
// Setters de posición
|
||||||
void setPos(SDL_FRect rect); // Establece posición y tamaño del objeto
|
void setPos(SDL_FRect rect); // Establece posición y tamaño del objeto
|
||||||
void setPos(float x, float y); // Establece posición x, y
|
void setPos(float x, float y); // Establece posición x, y
|
||||||
void setPosX(float value); // Establece posición X
|
void setPosX(float value); // Establece posición X
|
||||||
void setPosY(float value); // Establece posición Y
|
void setPosY(float value); // Establece posición Y
|
||||||
|
|
||||||
// Setters de velocidad
|
// Setters de velocidad
|
||||||
void setVelX(float value) { vx_ = value; }
|
void setVelX(float value) { vx_ = value; }
|
||||||
void setVelY(float value) { vy_ = value; }
|
void setVelY(float value) { vy_ = value; }
|
||||||
|
|
||||||
// Setters de aceleración
|
// Setters de aceleración
|
||||||
void setAccelX(float value) { ax_ = value; }
|
void setAccelX(float value) { ax_ = value; }
|
||||||
void setAccelY(float value) { ay_ = value; }
|
void setAccelY(float value) { ay_ = value; }
|
||||||
|
|
||||||
// Gestión de flip (volteo horizontal)
|
// Gestión de flip (volteo horizontal)
|
||||||
void setFlip(SDL_FlipMode flip) { flip_ = flip; } // Establece modo de flip
|
void setFlip(SDL_FlipMode flip) { flip_ = flip; } // Establece modo de flip
|
||||||
auto getFlip() -> SDL_FlipMode { return flip_; } // Obtiene modo de flip
|
auto getFlip() -> SDL_FlipMode { return flip_; } // Obtiene modo de flip
|
||||||
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; } // Alterna flip horizontal
|
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; } // Alterna flip horizontal
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Métodos protegidos
|
// Métodos protegidos
|
||||||
void move(float delta_time); // Mueve el sprite (time-based)
|
void move(float delta_time); // Mueve el sprite (time-based)
|
||||||
|
|
||||||
// Variables miembro - Posición
|
// Variables miembro - Posición
|
||||||
float x_{0.0F}; // Posición en el eje X
|
float x_{0.0F}; // Posición en el eje X
|
||||||
float y_{0.0F}; // Posición en el eje Y
|
float y_{0.0F}; // Posición en el eje Y
|
||||||
|
|
||||||
// Variables miembro - Velocidad (pixels/segundo)
|
// Variables miembro - Velocidad (pixels/segundo)
|
||||||
float vx_{0.0F}; // Velocidad en el eje X
|
float vx_{0.0F}; // Velocidad en el eje X
|
||||||
float vy_{0.0F}; // Velocidad en el eje Y
|
float vy_{0.0F}; // Velocidad en el eje Y
|
||||||
|
|
||||||
// Variables miembro - Aceleración (pixels/segundo²)
|
// Variables miembro - Aceleración (pixels/segundo²)
|
||||||
float ax_{0.0F}; // Aceleración en el eje X
|
float ax_{0.0F}; // Aceleración en el eje X
|
||||||
float ay_{0.0F}; // Aceleración en el eje Y
|
float ay_{0.0F}; // Aceleración en el eje Y
|
||||||
|
|
||||||
// Variables miembro - Renderizado
|
// Variables miembro - Renderizado
|
||||||
SDL_FlipMode flip_{SDL_FLIP_NONE}; // Modo de volteo del sprite
|
SDL_FlipMode flip_{SDL_FLIP_NONE}; // Modo de volteo del sprite
|
||||||
};
|
};
|
||||||
@@ -8,55 +8,55 @@ class Surface; // lines 5-5
|
|||||||
|
|
||||||
// Clase SurfaceSprite
|
// Clase SurfaceSprite
|
||||||
class SurfaceSprite {
|
class SurfaceSprite {
|
||||||
public:
|
public:
|
||||||
// Constructores
|
// Constructores
|
||||||
SurfaceSprite(std::shared_ptr<Surface>, float x, float y, float w, float h);
|
SurfaceSprite(std::shared_ptr<Surface>, float x, float y, float w, float h);
|
||||||
SurfaceSprite(std::shared_ptr<Surface>, SDL_FRect rect);
|
SurfaceSprite(std::shared_ptr<Surface>, SDL_FRect rect);
|
||||||
SurfaceSprite();
|
SurfaceSprite();
|
||||||
explicit SurfaceSprite(std::shared_ptr<Surface>);
|
explicit SurfaceSprite(std::shared_ptr<Surface>);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
virtual ~SurfaceSprite() = default;
|
virtual ~SurfaceSprite() = default;
|
||||||
|
|
||||||
// Actualización y renderizado
|
// Actualización y renderizado
|
||||||
virtual void update(float delta_time); // Actualiza el estado del sprite (time-based)
|
virtual void update(float delta_time); // Actualiza el estado del sprite (time-based)
|
||||||
virtual void render(); // Muestra el sprite por pantalla
|
virtual void render(); // Muestra el sprite por pantalla
|
||||||
virtual void render(Uint8 source_color, Uint8 target_color); // Renderiza con reemplazo de color
|
virtual void render(Uint8 source_color, Uint8 target_color); // Renderiza con reemplazo de color
|
||||||
virtual void renderWithVerticalFade(int fade_h, int canvas_height); // Renderiza amb dissolució vertical (hash 2D, sense parpelleig)
|
virtual void renderWithVerticalFade(int fade_h, int canvas_height); // Renderiza amb dissolució vertical (hash 2D, sense parpelleig)
|
||||||
virtual void renderWithVerticalFade(int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color); // Idem amb reemplaç de color
|
virtual void renderWithVerticalFade(int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color); // Idem amb reemplaç de color
|
||||||
|
|
||||||
// Gestión de estado
|
// Gestión de estado
|
||||||
virtual void clear(); // Reinicia las variables a cero
|
virtual void clear(); // Reinicia las variables a cero
|
||||||
|
|
||||||
// Obtención de propiedades
|
// Obtención de propiedades
|
||||||
[[nodiscard]] auto getX() const -> float { return pos_.x; }
|
[[nodiscard]] auto getX() const -> float { return pos_.x; }
|
||||||
[[nodiscard]] auto getY() const -> float { return pos_.y; }
|
[[nodiscard]] auto getY() const -> float { return pos_.y; }
|
||||||
[[nodiscard]] auto getWidth() const -> float { return pos_.w; }
|
[[nodiscard]] auto getWidth() const -> float { return pos_.w; }
|
||||||
[[nodiscard]] auto getHeight() const -> float { return pos_.h; }
|
[[nodiscard]] auto getHeight() const -> float { return pos_.h; }
|
||||||
[[nodiscard]] auto getPosition() const -> SDL_FRect { return pos_; }
|
[[nodiscard]] auto getPosition() const -> SDL_FRect { return pos_; }
|
||||||
[[nodiscard]] auto getClip() const -> SDL_FRect { return clip_; }
|
[[nodiscard]] auto getClip() const -> SDL_FRect { return clip_; }
|
||||||
[[nodiscard]] auto getSurface() const -> std::shared_ptr<Surface> { return surface_; }
|
[[nodiscard]] auto getSurface() const -> std::shared_ptr<Surface> { return surface_; }
|
||||||
auto getRect() -> SDL_FRect& { return pos_; }
|
auto getRect() -> SDL_FRect& { return pos_; }
|
||||||
|
|
||||||
// Modificación de posición y tamaño
|
// Modificación de posición y tamaño
|
||||||
void setX(float x) { pos_.x = x; }
|
void setX(float x) { pos_.x = x; }
|
||||||
void setY(float y) { pos_.y = y; }
|
void setY(float y) { pos_.y = y; }
|
||||||
void setWidth(float w) { pos_.w = w; }
|
void setWidth(float w) { pos_.w = w; }
|
||||||
void setHeight(float h) { pos_.h = h; }
|
void setHeight(float h) { pos_.h = h; }
|
||||||
void setPosition(float x, float y);
|
void setPosition(float x, float y);
|
||||||
void setPosition(SDL_FPoint p);
|
void setPosition(SDL_FPoint p);
|
||||||
void setPosition(SDL_FRect r) { pos_ = r; }
|
void setPosition(SDL_FRect r) { pos_ = r; }
|
||||||
void incX(float value) { pos_.x += value; }
|
void incX(float value) { pos_.x += value; }
|
||||||
void incY(float value) { pos_.y += value; }
|
void incY(float value) { pos_.y += value; }
|
||||||
|
|
||||||
// Modificación de clip y surface
|
// Modificación de clip y surface
|
||||||
void setClip(SDL_FRect rect) { clip_ = rect; }
|
void setClip(SDL_FRect rect) { clip_ = rect; }
|
||||||
void setClip(float x, float y, float w, float h) { clip_ = SDL_FRect{x, y, w, h}; }
|
void setClip(float x, float y, float w, float h) { clip_ = SDL_FRect{x, y, w, h}; }
|
||||||
void setSurface(std::shared_ptr<Surface> surface) { surface_ = std::move(surface); }
|
void setSurface(std::shared_ptr<Surface> surface) { surface_ = std::move(surface); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Variables miembro
|
// Variables miembro
|
||||||
std::shared_ptr<Surface> surface_{nullptr}; // Surface donde estan todos los dibujos del sprite
|
std::shared_ptr<Surface> surface_{nullptr}; // Surface donde estan todos los dibujos del sprite
|
||||||
SDL_FRect pos_{0.0F, 0.0F, 0.0F, 0.0F}; // Posición y tamaño donde dibujar el sprite
|
SDL_FRect pos_{0.0F, 0.0F, 0.0F, 0.0F}; // Posición y tamaño donde dibujar el sprite
|
||||||
SDL_FRect clip_{0.0F, 0.0F, 0.0F, 0.0F}; // Rectangulo de origen de la surface que se dibujará en pantalla
|
SDL_FRect clip_{0.0F, 0.0F, 0.0F, 0.0F}; // Rectangulo de origen de la surface que se dibujará en pantalla
|
||||||
};
|
};
|
||||||
@@ -11,54 +11,54 @@ class Surface; // lines 8-8
|
|||||||
|
|
||||||
// Clase texto. Pinta texto en pantalla a partir de un bitmap
|
// Clase texto. Pinta texto en pantalla a partir de un bitmap
|
||||||
class Text {
|
class Text {
|
||||||
public:
|
public:
|
||||||
// Tipos anidados públicos
|
// Tipos anidados públicos
|
||||||
struct Offset {
|
struct Offset {
|
||||||
int x{0}, y{0}, w{0};
|
int x{0}, y{0}, w{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct File {
|
struct File {
|
||||||
int box_width{0}; // Anchura de la caja de cada caracter en el png
|
int box_width{0}; // Anchura de la caja de cada caracter en el png
|
||||||
int box_height{0}; // Altura de la caja de cada caracter en el png
|
int box_height{0}; // Altura de la caja de cada caracter en el png
|
||||||
std::array<Offset, 128> offset{}; // Vector con las posiciones y ancho de cada letra
|
std::array<Offset, 128> offset{}; // Vector con las posiciones y ancho de cada letra
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Text(const std::shared_ptr<Surface>& surface, const std::string& text_file);
|
Text(const std::shared_ptr<Surface>& surface, const std::string& text_file);
|
||||||
Text(const std::shared_ptr<Surface>& surface, const std::shared_ptr<File>& text_file);
|
Text(const std::shared_ptr<Surface>& surface, const std::shared_ptr<File>& text_file);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Text() = default;
|
~Text() = default;
|
||||||
|
|
||||||
// Constantes de flags para writeDX
|
// Constantes de flags para writeDX
|
||||||
static constexpr int COLOR_FLAG = 1;
|
static constexpr int COLOR_FLAG = 1;
|
||||||
static constexpr int SHADOW_FLAG = 2;
|
static constexpr int SHADOW_FLAG = 2;
|
||||||
static constexpr int CENTER_FLAG = 4;
|
static constexpr int CENTER_FLAG = 4;
|
||||||
static constexpr int STROKE_FLAG = 8;
|
static constexpr int STROKE_FLAG = 8;
|
||||||
|
|
||||||
void write(int x, int y, const std::string& text, int kerning = 1, int lenght = -1); // Escribe el texto en pantalla
|
void write(int x, int y, const std::string& text, int kerning = 1, int lenght = -1); // Escribe el texto en pantalla
|
||||||
void writeColored(int x, int y, const std::string& text, Uint8 color, int kerning = 1, int lenght = -1); // Escribe el texto con colores
|
void writeColored(int x, int y, const std::string& text, Uint8 color, int kerning = 1, int lenght = -1); // Escribe el texto con colores
|
||||||
void writeShadowed(int x, int y, const std::string& text, Uint8 color, Uint8 shadow_distance = 1, int kerning = 1, int lenght = -1); // Escribe el texto con sombra
|
void writeShadowed(int x, int y, const std::string& text, Uint8 color, Uint8 shadow_distance = 1, int kerning = 1, int lenght = -1); // Escribe el texto con sombra
|
||||||
void writeCentered(int x, int y, const std::string& text, int kerning = 1, int lenght = -1); // Escribe el texto centrado en un punto x
|
void writeCentered(int x, int y, const std::string& text, int kerning = 1, int lenght = -1); // Escribe el texto centrado en un punto x
|
||||||
void writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1); // Escribe texto con extras
|
void writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1); // Escribe texto con extras
|
||||||
|
|
||||||
auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura
|
auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura
|
||||||
auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura
|
auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura
|
||||||
|
|
||||||
[[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena
|
[[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena
|
||||||
[[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter
|
[[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter
|
||||||
|
|
||||||
void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra
|
void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra
|
||||||
|
|
||||||
static auto loadTextFile(const std::string& file_path) -> std::shared_ptr<File>; // Método de utilidad para cargar ficheros de texto
|
static auto loadTextFile(const std::string& file_path) -> std::shared_ptr<File>; // Método de utilidad para cargar ficheros de texto
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Objetos y punteros
|
// Objetos y punteros
|
||||||
std::unique_ptr<SurfaceSprite> sprite_ = nullptr; // Objeto con los graficos para el texto
|
std::unique_ptr<SurfaceSprite> sprite_ = nullptr; // Objeto con los graficos para el texto
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
int box_width_ = 0; // Anchura de la caja de cada caracter en el png
|
int box_width_ = 0; // Anchura de la caja de cada caracter en el png
|
||||||
int box_height_ = 0; // Altura de la caja de cada caracter en el png
|
int box_height_ = 0; // Altura de la caja de cada caracter en el png
|
||||||
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija en todas las letras
|
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija en todas las letras
|
||||||
std::array<Offset, 128> offset_{}; // Vector con las posiciones y ancho de cada letra
|
std::array<Offset, 128> offset_{}; // Vector con las posiciones y ancho de cada letra
|
||||||
};
|
};
|
||||||
@@ -7,37 +7,37 @@
|
|||||||
struct Color; // lines 11-11
|
struct Color; // lines 11-11
|
||||||
|
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
explicit Texture(SDL_Renderer* renderer, std::string path = std::string()); // Constructor
|
explicit Texture(SDL_Renderer* renderer, std::string path = std::string()); // Constructor
|
||||||
~Texture(); // Destructor
|
~Texture(); // Destructor
|
||||||
|
|
||||||
auto loadFromFile(const std::string& path) -> bool; // Carga una imagen desde un fichero
|
auto loadFromFile(const std::string& path) -> bool; // Carga una imagen desde un fichero
|
||||||
auto createBlank(int width, int height, SDL_PixelFormat format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess access = SDL_TEXTUREACCESS_STREAMING) -> bool; // Crea una textura en blanco
|
auto createBlank(int width, int height, SDL_PixelFormat format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess access = SDL_TEXTUREACCESS_STREAMING) -> bool; // Crea una textura en blanco
|
||||||
auto reLoad() -> bool; // Recarga la textura
|
auto reLoad() -> bool; // Recarga la textura
|
||||||
|
|
||||||
void setColor(Uint8 red, Uint8 green, Uint8 blue); // Establece el color para la modulacion
|
void setColor(Uint8 red, Uint8 green, Uint8 blue); // Establece el color para la modulacion
|
||||||
void setColor(Color color); // Establece el color para la modulacion
|
void setColor(Color color); // Establece el color para la modulacion
|
||||||
void setBlendMode(SDL_BlendMode blending); // Establece el blending
|
void setBlendMode(SDL_BlendMode blending); // Establece el blending
|
||||||
void setAlpha(Uint8 alpha); // Establece el alpha para la modulación
|
void setAlpha(Uint8 alpha); // Establece el alpha para la modulación
|
||||||
void setAsRenderTarget(SDL_Renderer* renderer); // Establece la textura como objetivo de renderizado
|
void setAsRenderTarget(SDL_Renderer* renderer); // Establece la textura como objetivo de renderizado
|
||||||
|
|
||||||
void render(float x, float y, SDL_FRect* clip = nullptr, float zoom_w = 1, float zoom_h = 1, double angle = 0.0, SDL_FPoint* center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Renderiza la textura en un punto específico
|
void render(float x, float y, SDL_FRect* clip = nullptr, float zoom_w = 1, float zoom_h = 1, double angle = 0.0, SDL_FPoint* center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Renderiza la textura en un punto específico
|
||||||
|
|
||||||
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene el ancho de la imagen
|
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene el ancho de la imagen
|
||||||
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene el alto de la imagen
|
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene el alto de la imagen
|
||||||
auto getSDLTexture() -> SDL_Texture*; // Obtiene la textura
|
auto getSDLTexture() -> SDL_Texture*; // Obtiene la textura
|
||||||
auto getRenderer() -> SDL_Renderer*; // Obtiene el renderizador
|
auto getRenderer() -> SDL_Renderer*; // Obtiene el renderizador
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void unloadTexture(); // Libera la memoria de la textura
|
void unloadTexture(); // Libera la memoria de la textura
|
||||||
|
|
||||||
// Objetos y punteros
|
// Objetos y punteros
|
||||||
SDL_Renderer* renderer_; // Renderizador donde dibujar la textura
|
SDL_Renderer* renderer_; // Renderizador donde dibujar la textura
|
||||||
SDL_Texture* texture_ = nullptr; // La textura
|
SDL_Texture* texture_ = nullptr; // La textura
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
std::string path_; // Ruta de la imagen de la textura
|
std::string path_; // Ruta de la imagen de la textura
|
||||||
float width_ = 0.0F; // Ancho de la imagen
|
float width_ = 0.0F; // Ancho de la imagen
|
||||||
float height_ = 0.0F; // Alto de la imagen
|
float height_ = 0.0F; // Alto de la imagen
|
||||||
std::vector<std::vector<Uint32>> palettes_; // Vector con las diferentes paletas
|
std::vector<std::vector<Uint32>> palettes_; // Vector con las diferentes paletas
|
||||||
};
|
};
|
||||||
@@ -24,478 +24,478 @@ struct JA_Sound_t; // lines 18-18
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
|
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
|
||||||
Cache* Cache::cache = nullptr;
|
Cache* Cache::cache = nullptr;
|
||||||
|
|
||||||
// [SINGLETON] Crearemos el objeto cache con esta función estática
|
// [SINGLETON] Crearemos el objeto cache con esta función estática
|
||||||
void Cache::init() { Cache::cache = new Cache(); }
|
void Cache::init() { Cache::cache = new Cache(); }
|
||||||
|
|
||||||
// [SINGLETON] Destruiremos el objeto cache con esta función estática
|
// [SINGLETON] Destruiremos el objeto cache con esta función estática
|
||||||
void Cache::destroy() { delete Cache::cache; }
|
void Cache::destroy() { delete Cache::cache; }
|
||||||
|
|
||||||
// [SINGLETON] Con este método obtenemos el objeto cache y podemos trabajar con él
|
// [SINGLETON] Con este método obtenemos el objeto cache y podemos trabajar con él
|
||||||
auto Cache::get() -> Cache* { return Cache::cache; }
|
auto Cache::get() -> Cache* { return Cache::cache; }
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Cache::Cache()
|
Cache::Cache()
|
||||||
: loading_text_(Screen::get()->getText()) {
|
: loading_text_(Screen::get()->getText()) {
|
||||||
load();
|
load();
|
||||||
}
|
|
||||||
|
|
||||||
// Vacia todos los vectores de recursos
|
|
||||||
void Cache::clear() {
|
|
||||||
clearSounds();
|
|
||||||
clearMusics();
|
|
||||||
surfaces_.clear();
|
|
||||||
palettes_.clear();
|
|
||||||
text_files_.clear();
|
|
||||||
texts_.clear();
|
|
||||||
animations_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga todos los recursos
|
|
||||||
void Cache::load() {
|
|
||||||
calculateTotal();
|
|
||||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
|
||||||
std::cout << "\n** LOADING RESOURCES" << '\n';
|
|
||||||
loadSounds();
|
|
||||||
loadMusics();
|
|
||||||
loadSurfaces();
|
|
||||||
loadPalettes();
|
|
||||||
loadTextFiles();
|
|
||||||
loadAnimations();
|
|
||||||
loadRooms();
|
|
||||||
createText();
|
|
||||||
std::cout << "\n** RESOURCES LOADED" << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recarga todos los recursos
|
|
||||||
void Cache::reload() {
|
|
||||||
clear();
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtiene el sonido a partir de un nombre
|
|
||||||
auto Cache::getSound(const std::string& name) -> JA_Sound_t* {
|
|
||||||
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) { return s.name == name; });
|
|
||||||
|
|
||||||
if (it != sounds_.end()) {
|
|
||||||
return it->sound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Error: Sonido no encontrado " << name << '\n';
|
// Vacia todos los vectores de recursos
|
||||||
throw std::runtime_error("Sonido no encontrado: " + name);
|
void Cache::clear() {
|
||||||
}
|
clearSounds();
|
||||||
|
clearMusics();
|
||||||
// Obtiene la música a partir de un nombre
|
surfaces_.clear();
|
||||||
auto Cache::getMusic(const std::string& name) -> JA_Music_t* {
|
palettes_.clear();
|
||||||
auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; });
|
text_files_.clear();
|
||||||
|
texts_.clear();
|
||||||
if (it != musics_.end()) {
|
animations_.clear();
|
||||||
return it->music;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Error: Música no encontrada " << name << '\n';
|
// Carga todos los recursos
|
||||||
throw std::runtime_error("Música no encontrada: " + name);
|
void Cache::load() {
|
||||||
}
|
calculateTotal();
|
||||||
|
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||||
// Obtiene la surface a partir de un nombre
|
std::cout << "\n** LOADING RESOURCES" << '\n';
|
||||||
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
|
loadSounds();
|
||||||
auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) { return t.name == name; });
|
loadMusics();
|
||||||
|
loadSurfaces();
|
||||||
if (it != surfaces_.end()) {
|
loadPalettes();
|
||||||
return it->surface;
|
loadTextFiles();
|
||||||
|
loadAnimations();
|
||||||
|
loadRooms();
|
||||||
|
createText();
|
||||||
|
std::cout << "\n** RESOURCES LOADED" << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Error: Imagen no encontrada " << name << '\n';
|
// Recarga todos los recursos
|
||||||
throw std::runtime_error("Imagen no encontrada: " + name);
|
void Cache::reload() {
|
||||||
}
|
clear();
|
||||||
|
load();
|
||||||
// Obtiene la paleta a partir de un nombre
|
|
||||||
auto Cache::getPalette(const std::string& name) -> Palette {
|
|
||||||
auto it = std::ranges::find_if(palettes_, [&name](const auto& t) { return t.name == name; });
|
|
||||||
|
|
||||||
if (it != palettes_.end()) {
|
|
||||||
return it->palette;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Error: Paleta no encontrada " << name << '\n';
|
// Obtiene el sonido a partir de un nombre
|
||||||
throw std::runtime_error("Paleta no encontrada: " + name);
|
auto Cache::getSound(const std::string& name) -> JA_Sound_t* {
|
||||||
}
|
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) { return s.name == name; });
|
||||||
|
|
||||||
// Obtiene el fichero de texto a partir de un nombre
|
if (it != sounds_.end()) {
|
||||||
auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<Text::File> {
|
return it->sound;
|
||||||
auto it = std::ranges::find_if(text_files_, [&name](const auto& t) { return t.name == name; });
|
|
||||||
|
|
||||||
if (it != text_files_.end()) {
|
|
||||||
return it->text_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Error: TextFile no encontrado " << name << '\n';
|
|
||||||
throw std::runtime_error("TextFile no encontrado: " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtiene el objeto de texto a partir de un nombre
|
|
||||||
auto Cache::getText(const std::string& name) -> std::shared_ptr<Text> {
|
|
||||||
auto it = std::ranges::find_if(texts_, [&name](const auto& t) { return t.name == name; });
|
|
||||||
|
|
||||||
if (it != texts_.end()) {
|
|
||||||
return it->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Error: Text no encontrado " << name << '\n';
|
|
||||||
throw std::runtime_error("Texto no encontrado: " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtiene los datos de animación parseados a partir de un nombre
|
|
||||||
auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& {
|
|
||||||
auto it = std::ranges::find_if(animations_, [&name](const auto& a) { return a.name == name; });
|
|
||||||
|
|
||||||
if (it != animations_.end()) {
|
|
||||||
return *it;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Error: Animación no encontrada " << name << '\n';
|
|
||||||
throw std::runtime_error("Animación no encontrada: " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtiene la habitación a partir de un nombre
|
|
||||||
auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> {
|
|
||||||
auto it = std::ranges::find_if(rooms_, [&name](const auto& r) { return r.name == name; });
|
|
||||||
|
|
||||||
if (it != rooms_.end()) {
|
|
||||||
return it->room;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Error: Habitación no encontrada " << name << '\n';
|
|
||||||
throw std::runtime_error("Habitación no encontrada: " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtiene todas las habitaciones
|
|
||||||
auto Cache::getRooms() -> std::vector<RoomResource>& {
|
|
||||||
return rooms_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper para lanzar errores de carga con formato consistente
|
|
||||||
[[noreturn]] void Cache::throwLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e) {
|
|
||||||
std::cerr << "\n[ ERROR ] Failed to load " << asset_type << ": " << getFileName(file_path) << '\n';
|
|
||||||
std::cerr << "[ ERROR ] Path: " << file_path << '\n';
|
|
||||||
std::cerr << "[ ERROR ] Reason: " << e.what() << '\n';
|
|
||||||
std::cerr << "[ ERROR ] Check config/assets.yaml configuration\n";
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga los sonidos
|
|
||||||
void Cache::loadSounds() {
|
|
||||||
std::cout << "\n>> SOUND FILES" << '\n';
|
|
||||||
auto list = List::get()->getListByType(List::Type::SOUND);
|
|
||||||
sounds_.clear();
|
|
||||||
|
|
||||||
for (const auto& l : list) {
|
|
||||||
try {
|
|
||||||
auto name = getFileName(l);
|
|
||||||
JA_Sound_t* sound = nullptr;
|
|
||||||
|
|
||||||
// Try loading from resource pack first
|
|
||||||
auto audio_data = Helper::loadFile(l);
|
|
||||||
if (!audio_data.empty()) {
|
|
||||||
sound = JA_LoadSound(audio_data.data(), static_cast<Uint32>(audio_data.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to file path if memory loading failed
|
|
||||||
if (sound == nullptr) {
|
|
||||||
sound = JA_LoadSound(l.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sound == nullptr) {
|
|
||||||
throw std::runtime_error("Failed to decode audio file");
|
|
||||||
}
|
|
||||||
|
|
||||||
sounds_.emplace_back(SoundResource{.name = name, .sound = sound});
|
|
||||||
printWithDots("Sound : ", name, "[ LOADED ]");
|
|
||||||
updateLoadingProgress();
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
throwLoadError("SOUND", l, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: Sonido no encontrado " << name << '\n';
|
||||||
|
throw std::runtime_error("Sonido no encontrado: " + name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Carga las musicas
|
// Obtiene la música a partir de un nombre
|
||||||
void Cache::loadMusics() {
|
auto Cache::getMusic(const std::string& name) -> JA_Music_t* {
|
||||||
std::cout << "\n>> MUSIC FILES" << '\n';
|
auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; });
|
||||||
auto list = List::get()->getListByType(List::Type::MUSIC);
|
|
||||||
musics_.clear();
|
|
||||||
|
|
||||||
for (const auto& l : list) {
|
if (it != musics_.end()) {
|
||||||
try {
|
return it->music;
|
||||||
auto name = getFileName(l);
|
|
||||||
JA_Music_t* music = nullptr;
|
|
||||||
|
|
||||||
// Try loading from resource pack first
|
|
||||||
auto audio_data = Helper::loadFile(l);
|
|
||||||
if (!audio_data.empty()) {
|
|
||||||
music = JA_LoadMusic(audio_data.data(), static_cast<Uint32>(audio_data.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to file path if memory loading failed
|
|
||||||
if (music == nullptr) {
|
|
||||||
music = JA_LoadMusic(l.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (music == nullptr) {
|
|
||||||
throw std::runtime_error("Failed to decode music file");
|
|
||||||
}
|
|
||||||
|
|
||||||
musics_.emplace_back(MusicResource{.name = name, .music = music});
|
|
||||||
printWithDots("Music : ", name, "[ LOADED ]");
|
|
||||||
updateLoadingProgress(1);
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
throwLoadError("MUSIC", l, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: Música no encontrada " << name << '\n';
|
||||||
|
throw std::runtime_error("Música no encontrada: " + name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Carga las texturas
|
// Obtiene la surface a partir de un nombre
|
||||||
void Cache::loadSurfaces() {
|
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
|
||||||
std::cout << "\n>> SURFACES" << '\n';
|
auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) { return t.name == name; });
|
||||||
auto list = List::get()->getListByType(List::Type::BITMAP);
|
|
||||||
surfaces_.clear();
|
|
||||||
|
|
||||||
for (const auto& l : list) {
|
if (it != surfaces_.end()) {
|
||||||
try {
|
return it->surface;
|
||||||
auto name = getFileName(l);
|
}
|
||||||
surfaces_.emplace_back(SurfaceResource{.name = name, .surface = std::make_shared<Surface>(l)});
|
|
||||||
surfaces_.back().surface->setTransparentColor(0);
|
std::cerr << "Error: Imagen no encontrada " << name << '\n';
|
||||||
updateLoadingProgress();
|
throw std::runtime_error("Imagen no encontrada: " + name);
|
||||||
} catch (const std::exception& e) {
|
}
|
||||||
throwLoadError("BITMAP", l, e);
|
|
||||||
|
// Obtiene la paleta a partir de un nombre
|
||||||
|
auto Cache::getPalette(const std::string& name) -> Palette {
|
||||||
|
auto it = std::ranges::find_if(palettes_, [&name](const auto& t) { return t.name == name; });
|
||||||
|
|
||||||
|
if (it != palettes_.end()) {
|
||||||
|
return it->palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: Paleta no encontrada " << name << '\n';
|
||||||
|
throw std::runtime_error("Paleta no encontrada: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtiene el fichero de texto a partir de un nombre
|
||||||
|
auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<Text::File> {
|
||||||
|
auto it = std::ranges::find_if(text_files_, [&name](const auto& t) { return t.name == name; });
|
||||||
|
|
||||||
|
if (it != text_files_.end()) {
|
||||||
|
return it->text_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: TextFile no encontrado " << name << '\n';
|
||||||
|
throw std::runtime_error("TextFile no encontrado: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtiene el objeto de texto a partir de un nombre
|
||||||
|
auto Cache::getText(const std::string& name) -> std::shared_ptr<Text> {
|
||||||
|
auto it = std::ranges::find_if(texts_, [&name](const auto& t) { return t.name == name; });
|
||||||
|
|
||||||
|
if (it != texts_.end()) {
|
||||||
|
return it->text;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: Text no encontrado " << name << '\n';
|
||||||
|
throw std::runtime_error("Texto no encontrado: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtiene los datos de animación parseados a partir de un nombre
|
||||||
|
auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& {
|
||||||
|
auto it = std::ranges::find_if(animations_, [&name](const auto& a) { return a.name == name; });
|
||||||
|
|
||||||
|
if (it != animations_.end()) {
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: Animación no encontrada " << name << '\n';
|
||||||
|
throw std::runtime_error("Animación no encontrada: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtiene la habitación a partir de un nombre
|
||||||
|
auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> {
|
||||||
|
auto it = std::ranges::find_if(rooms_, [&name](const auto& r) { return r.name == name; });
|
||||||
|
|
||||||
|
if (it != rooms_.end()) {
|
||||||
|
return it->room;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Error: Habitación no encontrada " << name << '\n';
|
||||||
|
throw std::runtime_error("Habitación no encontrada: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtiene todas las habitaciones
|
||||||
|
auto Cache::getRooms() -> std::vector<RoomResource>& {
|
||||||
|
return rooms_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper para lanzar errores de carga con formato consistente
|
||||||
|
[[noreturn]] void Cache::throwLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e) {
|
||||||
|
std::cerr << "\n[ ERROR ] Failed to load " << asset_type << ": " << getFileName(file_path) << '\n';
|
||||||
|
std::cerr << "[ ERROR ] Path: " << file_path << '\n';
|
||||||
|
std::cerr << "[ ERROR ] Reason: " << e.what() << '\n';
|
||||||
|
std::cerr << "[ ERROR ] Check config/assets.yaml configuration\n";
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga los sonidos
|
||||||
|
void Cache::loadSounds() {
|
||||||
|
std::cout << "\n>> SOUND FILES" << '\n';
|
||||||
|
auto list = List::get()->getListByType(List::Type::SOUND);
|
||||||
|
sounds_.clear();
|
||||||
|
|
||||||
|
for (const auto& l : list) {
|
||||||
|
try {
|
||||||
|
auto name = getFileName(l);
|
||||||
|
JA_Sound_t* sound = nullptr;
|
||||||
|
|
||||||
|
// Try loading from resource pack first
|
||||||
|
auto audio_data = Helper::loadFile(l);
|
||||||
|
if (!audio_data.empty()) {
|
||||||
|
sound = JA_LoadSound(audio_data.data(), static_cast<Uint32>(audio_data.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to file path if memory loading failed
|
||||||
|
if (sound == nullptr) {
|
||||||
|
sound = JA_LoadSound(l.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sound == nullptr) {
|
||||||
|
throw std::runtime_error("Failed to decode audio file");
|
||||||
|
}
|
||||||
|
|
||||||
|
sounds_.emplace_back(SoundResource{.name = name, .sound = sound});
|
||||||
|
printWithDots("Sound : ", name, "[ LOADED ]");
|
||||||
|
updateLoadingProgress();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("SOUND", l, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconfigura el color transparente de algunas surfaces
|
// Carga las musicas
|
||||||
getSurface("loading_screen_color.gif")->setTransparentColor();
|
void Cache::loadMusics() {
|
||||||
getSurface("ending1.gif")->setTransparentColor();
|
std::cout << "\n>> MUSIC FILES" << '\n';
|
||||||
getSurface("ending2.gif")->setTransparentColor();
|
auto list = List::get()->getListByType(List::Type::MUSIC);
|
||||||
getSurface("ending3.gif")->setTransparentColor();
|
musics_.clear();
|
||||||
getSurface("ending4.gif")->setTransparentColor();
|
|
||||||
getSurface("ending5.gif")->setTransparentColor();
|
|
||||||
getSurface("standard.gif")->setTransparentColor(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga las paletas
|
for (const auto& l : list) {
|
||||||
void Cache::loadPalettes() {
|
try {
|
||||||
std::cout << "\n>> PALETTES" << '\n';
|
auto name = getFileName(l);
|
||||||
auto list = List::get()->getListByType(List::Type::PALETTE);
|
JA_Music_t* music = nullptr;
|
||||||
palettes_.clear();
|
|
||||||
|
|
||||||
for (const auto& l : list) {
|
// Try loading from resource pack first
|
||||||
try {
|
auto audio_data = Helper::loadFile(l);
|
||||||
auto name = getFileName(l);
|
if (!audio_data.empty()) {
|
||||||
palettes_.emplace_back(ResourcePalette{.name = name, .palette = readPalFile(l)});
|
music = JA_LoadMusic(audio_data.data(), static_cast<Uint32>(audio_data.size()));
|
||||||
updateLoadingProgress();
|
}
|
||||||
} catch (const std::exception& e) {
|
|
||||||
throwLoadError("PALETTE", l, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga los ficheros de texto
|
// Fallback to file path if memory loading failed
|
||||||
void Cache::loadTextFiles() {
|
if (music == nullptr) {
|
||||||
std::cout << "\n>> TEXT FILES" << '\n';
|
music = JA_LoadMusic(l.c_str());
|
||||||
auto list = List::get()->getListByType(List::Type::FONT);
|
}
|
||||||
text_files_.clear();
|
|
||||||
|
|
||||||
for (const auto& l : list) {
|
if (music == nullptr) {
|
||||||
try {
|
throw std::runtime_error("Failed to decode music file");
|
||||||
auto name = getFileName(l);
|
}
|
||||||
text_files_.emplace_back(TextFileResource{.name = name, .text_file = Text::loadTextFile(l)});
|
|
||||||
updateLoadingProgress();
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
throwLoadError("FONT", l, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga las animaciones
|
musics_.emplace_back(MusicResource{.name = name, .music = music});
|
||||||
void Cache::loadAnimations() {
|
printWithDots("Music : ", name, "[ LOADED ]");
|
||||||
std::cout << "\n>> ANIMATIONS" << '\n';
|
updateLoadingProgress(1);
|
||||||
auto list = List::get()->getListByType(List::Type::ANIMATION);
|
} catch (const std::exception& e) {
|
||||||
animations_.clear();
|
throwLoadError("MUSIC", l, e);
|
||||||
|
|
||||||
for (const auto& l : list) {
|
|
||||||
try {
|
|
||||||
auto name = getFileName(l);
|
|
||||||
|
|
||||||
// Cargar bytes del archivo YAML sin parsear (carga lazy)
|
|
||||||
auto yaml_bytes = Helper::loadFile(l);
|
|
||||||
|
|
||||||
if (yaml_bytes.empty()) {
|
|
||||||
throw std::runtime_error("File is empty or could not be loaded");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
animations_.emplace_back(AnimationResource{.name = name, .yaml_data = yaml_bytes});
|
|
||||||
printWithDots("Animation : ", name, "[ LOADED ]");
|
|
||||||
updateLoadingProgress();
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
throwLoadError("ANIMATION", l, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Carga las habitaciones desde archivos YAML
|
// Carga las texturas
|
||||||
void Cache::loadRooms() {
|
void Cache::loadSurfaces() {
|
||||||
std::cout << "\n>> ROOMS" << '\n';
|
std::cout << "\n>> SURFACES" << '\n';
|
||||||
auto list = List::get()->getListByType(List::Type::ROOM);
|
auto list = List::get()->getListByType(List::Type::BITMAP);
|
||||||
rooms_.clear();
|
surfaces_.clear();
|
||||||
|
|
||||||
for (const auto& l : list) {
|
for (const auto& l : list) {
|
||||||
try {
|
try {
|
||||||
auto name = getFileName(l);
|
auto name = getFileName(l);
|
||||||
rooms_.emplace_back(RoomResource{.name = name, .room = std::make_shared<Room::Data>(Room::loadYAML(l))});
|
surfaces_.emplace_back(SurfaceResource{.name = name, .surface = std::make_shared<Surface>(l)});
|
||||||
printWithDots("Room : ", name, "[ LOADED ]");
|
surfaces_.back().surface->setTransparentColor(0);
|
||||||
updateLoadingProgress();
|
updateLoadingProgress();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
throwLoadError("ROOM", l, e);
|
throwLoadError("BITMAP", l, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconfigura el color transparente de algunas surfaces
|
||||||
|
getSurface("loading_screen_color.gif")->setTransparentColor();
|
||||||
|
getSurface("ending1.gif")->setTransparentColor();
|
||||||
|
getSurface("ending2.gif")->setTransparentColor();
|
||||||
|
getSurface("ending3.gif")->setTransparentColor();
|
||||||
|
getSurface("ending4.gif")->setTransparentColor();
|
||||||
|
getSurface("ending5.gif")->setTransparentColor();
|
||||||
|
getSurface("standard.gif")->setTransparentColor(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga las paletas
|
||||||
|
void Cache::loadPalettes() {
|
||||||
|
std::cout << "\n>> PALETTES" << '\n';
|
||||||
|
auto list = List::get()->getListByType(List::Type::PALETTE);
|
||||||
|
palettes_.clear();
|
||||||
|
|
||||||
|
for (const auto& l : list) {
|
||||||
|
try {
|
||||||
|
auto name = getFileName(l);
|
||||||
|
palettes_.emplace_back(ResourcePalette{.name = name, .palette = readPalFile(l)});
|
||||||
|
updateLoadingProgress();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("PALETTE", l, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Cache::createText() {
|
// Carga los ficheros de texto
|
||||||
struct ResourceInfo {
|
void Cache::loadTextFiles() {
|
||||||
|
std::cout << "\n>> TEXT FILES" << '\n';
|
||||||
|
auto list = List::get()->getListByType(List::Type::FONT);
|
||||||
|
text_files_.clear();
|
||||||
|
|
||||||
|
for (const auto& l : list) {
|
||||||
|
try {
|
||||||
|
auto name = getFileName(l);
|
||||||
|
text_files_.emplace_back(TextFileResource{.name = name, .text_file = Text::loadTextFile(l)});
|
||||||
|
updateLoadingProgress();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("FONT", l, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga las animaciones
|
||||||
|
void Cache::loadAnimations() {
|
||||||
|
std::cout << "\n>> ANIMATIONS" << '\n';
|
||||||
|
auto list = List::get()->getListByType(List::Type::ANIMATION);
|
||||||
|
animations_.clear();
|
||||||
|
|
||||||
|
for (const auto& l : list) {
|
||||||
|
try {
|
||||||
|
auto name = getFileName(l);
|
||||||
|
|
||||||
|
// Cargar bytes del archivo YAML sin parsear (carga lazy)
|
||||||
|
auto yaml_bytes = Helper::loadFile(l);
|
||||||
|
|
||||||
|
if (yaml_bytes.empty()) {
|
||||||
|
throw std::runtime_error("File is empty or could not be loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
animations_.emplace_back(AnimationResource{.name = name, .yaml_data = yaml_bytes});
|
||||||
|
printWithDots("Animation : ", name, "[ LOADED ]");
|
||||||
|
updateLoadingProgress();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("ANIMATION", l, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga las habitaciones desde archivos YAML
|
||||||
|
void Cache::loadRooms() {
|
||||||
|
std::cout << "\n>> ROOMS" << '\n';
|
||||||
|
auto list = List::get()->getListByType(List::Type::ROOM);
|
||||||
|
rooms_.clear();
|
||||||
|
|
||||||
|
for (const auto& l : list) {
|
||||||
|
try {
|
||||||
|
auto name = getFileName(l);
|
||||||
|
rooms_.emplace_back(RoomResource{.name = name, .room = std::make_shared<Room::Data>(Room::loadYAML(l))});
|
||||||
|
printWithDots("Room : ", name, "[ LOADED ]");
|
||||||
|
updateLoadingProgress();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throwLoadError("ROOM", l, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cache::createText() {
|
||||||
|
struct ResourceInfo {
|
||||||
std::string key; // Identificador del recurso
|
std::string key; // Identificador del recurso
|
||||||
std::string texture_file; // Nombre del archivo de textura
|
std::string texture_file; // Nombre del archivo de textura
|
||||||
std::string text_file; // Nombre del archivo de texto
|
std::string text_file; // Nombre del archivo de texto
|
||||||
};
|
};
|
||||||
|
|
||||||
std::cout << "\n>> CREATING TEXT_OBJECTS" << '\n';
|
std::cout << "\n>> CREATING TEXT_OBJECTS" << '\n';
|
||||||
|
|
||||||
std::vector<ResourceInfo> resources = {
|
std::vector<ResourceInfo> resources = {
|
||||||
{.key = "aseprite", .texture_file = "aseprite.gif", .text_file = "aseprite.txt"},
|
{.key = "aseprite", .texture_file = "aseprite.gif", .text_file = "aseprite.txt"},
|
||||||
{.key = "gauntlet", .texture_file = "gauntlet.gif", .text_file = "gauntlet.txt"},
|
{.key = "gauntlet", .texture_file = "gauntlet.gif", .text_file = "gauntlet.txt"},
|
||||||
{.key = "smb2", .texture_file = "smb2.gif", .text_file = "smb2.txt"},
|
{.key = "smb2", .texture_file = "smb2.gif", .text_file = "smb2.txt"},
|
||||||
{.key = "subatomic", .texture_file = "subatomic.gif", .text_file = "subatomic.txt"},
|
{.key = "subatomic", .texture_file = "subatomic.gif", .text_file = "subatomic.txt"},
|
||||||
{.key = "8bithud", .texture_file = "8bithud.gif", .text_file = "8bithud.txt"}};
|
{.key = "8bithud", .texture_file = "8bithud.gif", .text_file = "8bithud.txt"}};
|
||||||
|
|
||||||
for (const auto& res_info : resources) {
|
for (const auto& res_info : resources) {
|
||||||
texts_.emplace_back(TextResource{.name = res_info.key, .text = std::make_shared<Text>(getSurface(res_info.texture_file), getTextFile(res_info.text_file))});
|
texts_.emplace_back(TextResource{.name = res_info.key, .text = std::make_shared<Text>(getSurface(res_info.texture_file), getTextFile(res_info.text_file))});
|
||||||
printWithDots("Text : ", res_info.key, "[ DONE ]");
|
printWithDots("Text : ", res_info.key, "[ DONE ]");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vacía el vector de sonidos
|
|
||||||
void Cache::clearSounds() {
|
|
||||||
// Itera sobre el vector y libera los recursos asociados a cada JA_Sound_t
|
|
||||||
for (auto& sound : sounds_) {
|
|
||||||
if (sound.sound != nullptr) {
|
|
||||||
JA_DeleteSound(sound.sound);
|
|
||||||
sound.sound = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sounds_.clear(); // Limpia el vector después de liberar todos los recursos
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vacía el vector de musicas
|
// Vacía el vector de sonidos
|
||||||
void Cache::clearMusics() {
|
void Cache::clearSounds() {
|
||||||
// Itera sobre el vector y libera los recursos asociados a cada JA_Music_t
|
// Itera sobre el vector y libera los recursos asociados a cada JA_Sound_t
|
||||||
for (auto& music : musics_) {
|
for (auto& sound : sounds_) {
|
||||||
if (music.music != nullptr) {
|
if (sound.sound != nullptr) {
|
||||||
JA_DeleteMusic(music.music);
|
JA_DeleteSound(sound.sound);
|
||||||
music.music = nullptr;
|
sound.sound = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
sounds_.clear(); // Limpia el vector después de liberar todos los recursos
|
||||||
musics_.clear(); // Limpia el vector después de liberar todos los recursos
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcula el numero de recursos para cargar
|
|
||||||
void Cache::calculateTotal() {
|
|
||||||
std::vector<List::Type> asset_types = {
|
|
||||||
List::Type::SOUND,
|
|
||||||
List::Type::MUSIC,
|
|
||||||
List::Type::BITMAP,
|
|
||||||
List::Type::PALETTE,
|
|
||||||
List::Type::FONT,
|
|
||||||
List::Type::ANIMATION,
|
|
||||||
List::Type::ROOM};
|
|
||||||
|
|
||||||
int total = 0;
|
|
||||||
for (const auto& asset_type : asset_types) {
|
|
||||||
auto list = List::get()->getListByType(asset_type);
|
|
||||||
total += list.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count_ = ResourceCount{.total = total, .loaded = 0};
|
// Vacía el vector de musicas
|
||||||
}
|
void Cache::clearMusics() {
|
||||||
|
// Itera sobre el vector y libera los recursos asociados a cada JA_Music_t
|
||||||
|
for (auto& music : musics_) {
|
||||||
|
if (music.music != nullptr) {
|
||||||
|
JA_DeleteMusic(music.music);
|
||||||
|
music.music = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
musics_.clear(); // Limpia el vector después de liberar todos los recursos
|
||||||
|
}
|
||||||
|
|
||||||
// Muestra el progreso de carga
|
// Calcula el numero de recursos para cargar
|
||||||
void Cache::renderProgress() {
|
void Cache::calculateTotal() {
|
||||||
constexpr float X_PADDING = 60.0F;
|
std::vector<List::Type> asset_types = {
|
||||||
constexpr float Y_PADDING = 10.0F;
|
List::Type::SOUND,
|
||||||
constexpr float BAR_HEIGHT = 5.0F;
|
List::Type::MUSIC,
|
||||||
|
List::Type::BITMAP,
|
||||||
|
List::Type::PALETTE,
|
||||||
|
List::Type::FONT,
|
||||||
|
List::Type::ANIMATION,
|
||||||
|
List::Type::ROOM};
|
||||||
|
|
||||||
const float BAR_POSITION = Options::game.height - BAR_HEIGHT - Y_PADDING;
|
int total = 0;
|
||||||
Screen::get()->start();
|
for (const auto& asset_type : asset_types) {
|
||||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
auto list = List::get()->getListByType(asset_type);
|
||||||
|
total += list.size();
|
||||||
|
}
|
||||||
|
|
||||||
auto surface = Screen::get()->getRendererSurface();
|
count_ = ResourceCount{.total = total, .loaded = 0};
|
||||||
const auto LOADING_TEXT_COLOR = static_cast<Uint8>(PaletteColor::BRIGHT_WHITE);
|
}
|
||||||
const auto BAR_COLOR = static_cast<Uint8>(PaletteColor::WHITE);
|
|
||||||
const int TEXT_HEIGHT = loading_text_->getCharacterSize();
|
|
||||||
const int CENTER_X = Options::game.width / 2;
|
|
||||||
const int CENTER_Y = Options::game.height / 2;
|
|
||||||
|
|
||||||
// Draw APP_NAME centered above center
|
// Muestra el progreso de carga
|
||||||
const std::string APP_NAME = spaceBetweenLetters(Version::APP_NAME);
|
void Cache::renderProgress() {
|
||||||
loading_text_->writeColored(
|
constexpr float X_PADDING = 60.0F;
|
||||||
CENTER_X - (loading_text_->length(APP_NAME) / 2),
|
constexpr float Y_PADDING = 10.0F;
|
||||||
CENTER_Y - TEXT_HEIGHT,
|
constexpr float BAR_HEIGHT = 5.0F;
|
||||||
APP_NAME,
|
|
||||||
LOADING_TEXT_COLOR);
|
|
||||||
|
|
||||||
// Draw VERSION centered below center
|
const float BAR_POSITION = Options::game.height - BAR_HEIGHT - Y_PADDING;
|
||||||
const std::string VERSION_TEXT = "ver. " + std::string(Texts::VERSION) + " (" + std::string(Version::GIT_HASH) + ")";
|
Screen::get()->start();
|
||||||
loading_text_->writeColored(
|
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||||
CENTER_X - (loading_text_->length(VERSION_TEXT) / 2),
|
|
||||||
CENTER_Y + TEXT_HEIGHT,
|
|
||||||
VERSION_TEXT,
|
|
||||||
LOADING_TEXT_COLOR);
|
|
||||||
|
|
||||||
// Draw progress bar border
|
auto surface = Screen::get()->getRendererSurface();
|
||||||
const float WIRED_BAR_WIDTH = Options::game.width - (X_PADDING * 2);
|
const auto LOADING_TEXT_COLOR = static_cast<Uint8>(PaletteColor::BRIGHT_WHITE);
|
||||||
SDL_FRect rect_wired = {X_PADDING, BAR_POSITION, WIRED_BAR_WIDTH, BAR_HEIGHT};
|
const auto BAR_COLOR = static_cast<Uint8>(PaletteColor::WHITE);
|
||||||
surface->drawRectBorder(&rect_wired, BAR_COLOR);
|
const int TEXT_HEIGHT = loading_text_->getCharacterSize();
|
||||||
|
const int CENTER_X = Options::game.width / 2;
|
||||||
|
const int CENTER_Y = Options::game.height / 2;
|
||||||
|
|
||||||
// Draw progress bar fill
|
// Draw APP_NAME centered above center
|
||||||
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * count_.getPercentage();
|
const std::string APP_NAME = spaceBetweenLetters(Version::APP_NAME);
|
||||||
SDL_FRect rect_full = {X_PADDING, BAR_POSITION, FULL_BAR_WIDTH, BAR_HEIGHT};
|
loading_text_->writeColored(
|
||||||
surface->fillRect(&rect_full, BAR_COLOR);
|
CENTER_X - (loading_text_->length(APP_NAME) / 2),
|
||||||
|
CENTER_Y - TEXT_HEIGHT,
|
||||||
|
APP_NAME,
|
||||||
|
LOADING_TEXT_COLOR);
|
||||||
|
|
||||||
Screen::get()->render();
|
// Draw VERSION centered below center
|
||||||
}
|
const std::string VERSION_TEXT = "ver. " + std::string(Texts::VERSION) + " (" + std::string(Version::GIT_HASH) + ")";
|
||||||
|
loading_text_->writeColored(
|
||||||
|
CENTER_X - (loading_text_->length(VERSION_TEXT) / 2),
|
||||||
|
CENTER_Y + TEXT_HEIGHT,
|
||||||
|
VERSION_TEXT,
|
||||||
|
LOADING_TEXT_COLOR);
|
||||||
|
|
||||||
// Comprueba los eventos de la pantalla de carga
|
// Draw progress bar border
|
||||||
void Cache::checkEvents() {
|
const float WIRED_BAR_WIDTH = Options::game.width - (X_PADDING * 2);
|
||||||
SDL_Event event;
|
SDL_FRect rect_wired = {X_PADDING, BAR_POSITION, WIRED_BAR_WIDTH, BAR_HEIGHT};
|
||||||
while (SDL_PollEvent(&event)) {
|
surface->drawRectBorder(&rect_wired, BAR_COLOR);
|
||||||
switch (event.type) {
|
|
||||||
case SDL_EVENT_QUIT:
|
// Draw progress bar fill
|
||||||
exit(0);
|
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * count_.getPercentage();
|
||||||
break;
|
SDL_FRect rect_full = {X_PADDING, BAR_POSITION, FULL_BAR_WIDTH, BAR_HEIGHT};
|
||||||
case SDL_EVENT_KEY_DOWN:
|
surface->fillRect(&rect_full, BAR_COLOR);
|
||||||
if (event.key.key == SDLK_ESCAPE) {
|
|
||||||
|
Screen::get()->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comprueba los eventos de la pantalla de carga
|
||||||
|
void Cache::checkEvents() {
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
break;
|
||||||
break;
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
if (event.key.key == SDLK_ESCAPE) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Actualiza el progreso de carga
|
// Actualiza el progreso de carga
|
||||||
void Cache::updateLoadingProgress(int steps) {
|
void Cache::updateLoadingProgress(int steps) {
|
||||||
count_.add(1);
|
count_.add(1);
|
||||||
if (count_.loaded % steps == 0 || count_.loaded == count_.total) {
|
if (count_.loaded % steps == 0 || count_.loaded == count_.total) {
|
||||||
renderProgress();
|
renderProgress();
|
||||||
|
}
|
||||||
|
checkEvents();
|
||||||
}
|
}
|
||||||
checkEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
class Cache {
|
class Cache {
|
||||||
public:
|
public:
|
||||||
static void init(); // Inicialización singleton
|
static void init(); // Inicialización singleton
|
||||||
static void destroy(); // Destrucción singleton
|
static void destroy(); // Destrucción singleton
|
||||||
static auto get() -> Cache*; // Acceso al singleton
|
static auto get() -> Cache*; // Acceso al singleton
|
||||||
@@ -27,21 +27,21 @@ class Cache {
|
|||||||
|
|
||||||
void reload(); // Recarga todos los recursos
|
void reload(); // Recarga todos los recursos
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Estructura para llevar la cuenta de los recursos cargados
|
// Estructura para llevar la cuenta de los recursos cargados
|
||||||
struct ResourceCount {
|
struct ResourceCount {
|
||||||
int total{0}; // Número total de recursos
|
int total{0}; // Número total de recursos
|
||||||
int loaded{0}; // Número de recursos cargados
|
int loaded{0}; // Número de recursos cargados
|
||||||
|
|
||||||
// Añade una cantidad a los recursos cargados
|
// Añade una cantidad a los recursos cargados
|
||||||
void add(int amount) {
|
void add(int amount) {
|
||||||
loaded += amount;
|
loaded += amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene el porcentaje de recursos cargados
|
// Obtiene el porcentaje de recursos cargados
|
||||||
[[nodiscard]] auto getPercentage() const -> float {
|
[[nodiscard]] auto getPercentage() const -> float {
|
||||||
return static_cast<float>(loaded) / static_cast<float>(total);
|
return static_cast<float>(loaded) / static_cast<float>(total);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Métodos de carga de recursos
|
// Métodos de carga de recursos
|
||||||
@@ -88,6 +88,6 @@ class Cache {
|
|||||||
|
|
||||||
ResourceCount count_{}; // Contador de recursos
|
ResourceCount count_{}; // Contador de recursos
|
||||||
std::shared_ptr<Text> loading_text_; // Texto para la pantalla de carga
|
std::shared_ptr<Text> loading_text_; // Texto para la pantalla de carga
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -12,171 +12,171 @@
|
|||||||
|
|
||||||
namespace Resource::Helper {
|
namespace Resource::Helper {
|
||||||
|
|
||||||
static bool resource_system_initialized = false;
|
static bool resource_system_initialized = false;
|
||||||
|
|
||||||
// Initialize the resource system
|
// Initialize the resource system
|
||||||
auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback)
|
auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback)
|
||||||
-> bool {
|
-> bool {
|
||||||
if (resource_system_initialized) {
|
if (resource_system_initialized) {
|
||||||
std::cout << "ResourceHelper: Already initialized\n";
|
std::cout << "ResourceHelper: Already initialized\n";
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "ResourceHelper: Initializing with pack: " << pack_file << '\n';
|
|
||||||
std::cout << "ResourceHelper: Fallback enabled: " << (enable_fallback ? "Yes" : "No")
|
|
||||||
<< '\n';
|
|
||||||
|
|
||||||
bool success = Loader::get().initialize(pack_file, enable_fallback);
|
|
||||||
if (success) {
|
|
||||||
resource_system_initialized = true;
|
|
||||||
std::cout << "ResourceHelper: Initialization successful\n";
|
|
||||||
} else {
|
|
||||||
std::cerr << "ResourceHelper: Initialization failed\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown the resource system
|
|
||||||
void shutdownResourceSystem() {
|
|
||||||
if (resource_system_initialized) {
|
|
||||||
Loader::get().shutdown();
|
|
||||||
resource_system_initialized = false;
|
|
||||||
std::cout << "ResourceHelper: Shutdown complete\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load a file
|
|
||||||
auto loadFile(const std::string& filepath) -> std::vector<uint8_t> {
|
|
||||||
if (!resource_system_initialized) {
|
|
||||||
std::cerr << "ResourceHelper: System not initialized, loading from filesystem\n";
|
|
||||||
// Fallback to direct filesystem access
|
|
||||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
|
||||||
if (!file) {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
std::streamsize file_size = file.tellg();
|
|
||||||
file.seekg(0, std::ios::beg);
|
std::cout << "ResourceHelper: Initializing with pack: " << pack_file << '\n';
|
||||||
std::vector<uint8_t> data(file_size);
|
std::cout << "ResourceHelper: Fallback enabled: " << (enable_fallback ? "Yes" : "No")
|
||||||
file.read(reinterpret_cast<char*>(data.data()), file_size);
|
<< '\n';
|
||||||
return data;
|
|
||||||
|
bool success = Loader::get().initialize(pack_file, enable_fallback);
|
||||||
|
if (success) {
|
||||||
|
resource_system_initialized = true;
|
||||||
|
std::cout << "ResourceHelper: Initialization successful\n";
|
||||||
|
} else {
|
||||||
|
std::cerr << "ResourceHelper: Initialization failed\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if we should use the pack
|
// Shutdown the resource system
|
||||||
if (shouldUseResourcePack(filepath)) {
|
void shutdownResourceSystem() {
|
||||||
// Convert to pack path
|
if (resource_system_initialized) {
|
||||||
std::string pack_path = getPackPath(filepath);
|
Loader::get().shutdown();
|
||||||
|
resource_system_initialized = false;
|
||||||
|
std::cout << "ResourceHelper: Shutdown complete\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Try to load from pack
|
// Load a file
|
||||||
auto data = Loader::get().loadResource(pack_path);
|
auto loadFile(const std::string& filepath) -> std::vector<uint8_t> {
|
||||||
if (!data.empty()) {
|
if (!resource_system_initialized) {
|
||||||
|
std::cerr << "ResourceHelper: System not initialized, loading from filesystem\n";
|
||||||
|
// Fallback to direct filesystem access
|
||||||
|
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::streamsize file_size = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
std::vector<uint8_t> data(file_size);
|
||||||
|
file.read(reinterpret_cast<char*>(data.data()), file_size);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If pack loading failed, try filesystem as fallback
|
// Determine if we should use the pack
|
||||||
std::cerr << "ResourceHelper: Pack failed for " << pack_path
|
if (shouldUseResourcePack(filepath)) {
|
||||||
<< ", trying filesystem\n";
|
// Convert to pack path
|
||||||
|
std::string pack_path = getPackPath(filepath);
|
||||||
|
|
||||||
|
// Try to load from pack
|
||||||
|
auto data = Loader::get().loadResource(pack_path);
|
||||||
|
if (!data.empty()) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If pack loading failed, try filesystem as fallback
|
||||||
|
std::cerr << "ResourceHelper: Pack failed for " << pack_path
|
||||||
|
<< ", trying filesystem\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load from filesystem
|
||||||
|
return Loader::get().loadResource(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load from filesystem
|
// Check if a file exists
|
||||||
return Loader::get().loadResource(filepath);
|
auto fileExists(const std::string& filepath) -> bool {
|
||||||
}
|
if (!resource_system_initialized) {
|
||||||
|
return std::filesystem::exists(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if a file exists
|
// Check pack if appropriate
|
||||||
auto fileExists(const std::string& filepath) -> bool {
|
if (shouldUseResourcePack(filepath)) {
|
||||||
if (!resource_system_initialized) {
|
std::string pack_path = getPackPath(filepath);
|
||||||
|
if (Loader::get().resourceExists(pack_path)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check filesystem
|
||||||
return std::filesystem::exists(filepath);
|
return std::filesystem::exists(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check pack if appropriate
|
// Convert asset path to pack path
|
||||||
if (shouldUseResourcePack(filepath)) {
|
auto getPackPath(const std::string& asset_path) -> std::string {
|
||||||
std::string pack_path = getPackPath(filepath);
|
std::string path = asset_path;
|
||||||
if (Loader::get().resourceExists(pack_path)) {
|
|
||||||
|
// Convert backslashes to forward slashes
|
||||||
|
std::ranges::replace(path, '\\', '/');
|
||||||
|
|
||||||
|
// If it's an absolute path containing "/data/", extract everything after "/data/"
|
||||||
|
// This handles paths like: /Users/sergio/.../data/palette/file.pal -> palette/file.pal
|
||||||
|
size_t data_pos = path.find("/data/");
|
||||||
|
if (data_pos != std::string::npos) {
|
||||||
|
return path.substr(data_pos + 6); // +6 to skip "/data/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove leading slashes
|
||||||
|
while (!path.empty() && path[0] == '/') {
|
||||||
|
path = path.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "./" prefix if present
|
||||||
|
if (path.starts_with("./")) {
|
||||||
|
path = path.substr(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "../" prefixes (for macOS bundle paths in development)
|
||||||
|
while (path.starts_with("../")) {
|
||||||
|
path = path.substr(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "Resources/" prefix if present (for macOS bundle)
|
||||||
|
const std::string RESOURCES_PREFIX = "Resources/";
|
||||||
|
if (path.starts_with(RESOURCES_PREFIX)) {
|
||||||
|
path = path.substr(RESOURCES_PREFIX.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove "data/" prefix if present
|
||||||
|
const std::string DATA_PREFIX = "data/";
|
||||||
|
if (path.starts_with(DATA_PREFIX)) {
|
||||||
|
path = path.substr(DATA_PREFIX.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file should use resource pack
|
||||||
|
auto shouldUseResourcePack(const std::string& filepath) -> bool {
|
||||||
|
std::string path = filepath;
|
||||||
|
std::ranges::replace(path, '\\', '/');
|
||||||
|
|
||||||
|
// Don't use pack for most config files (except config/assets.yaml which is loaded
|
||||||
|
// directly via Loader::loadAssetsConfig() in release builds)
|
||||||
|
if (path.find("config/") != std::string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use pack for data files
|
||||||
|
if (path.find("data/") != std::string::npos) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check filesystem
|
// Check if it looks like a data file (has common extensions)
|
||||||
return std::filesystem::exists(filepath);
|
if (path.find(".ogg") != std::string::npos || path.find(".wav") != std::string::npos ||
|
||||||
}
|
path.find(".gif") != std::string::npos || path.find(".png") != std::string::npos ||
|
||||||
|
path.find(".pal") != std::string::npos || path.find(".yaml") != std::string::npos ||
|
||||||
|
path.find(".txt") != std::string::npos || path.find(".glsl") != std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert asset path to pack path
|
|
||||||
auto getPackPath(const std::string& asset_path) -> std::string {
|
|
||||||
std::string path = asset_path;
|
|
||||||
|
|
||||||
// Convert backslashes to forward slashes
|
|
||||||
std::ranges::replace(path, '\\', '/');
|
|
||||||
|
|
||||||
// If it's an absolute path containing "/data/", extract everything after "/data/"
|
|
||||||
// This handles paths like: /Users/sergio/.../data/palette/file.pal -> palette/file.pal
|
|
||||||
size_t data_pos = path.find("/data/");
|
|
||||||
if (data_pos != std::string::npos) {
|
|
||||||
return path.substr(data_pos + 6); // +6 to skip "/data/"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove leading slashes
|
|
||||||
while (!path.empty() && path[0] == '/') {
|
|
||||||
path = path.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove "./" prefix if present
|
|
||||||
if (path.starts_with("./")) {
|
|
||||||
path = path.substr(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove "../" prefixes (for macOS bundle paths in development)
|
|
||||||
while (path.starts_with("../")) {
|
|
||||||
path = path.substr(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove "Resources/" prefix if present (for macOS bundle)
|
|
||||||
const std::string RESOURCES_PREFIX = "Resources/";
|
|
||||||
if (path.starts_with(RESOURCES_PREFIX)) {
|
|
||||||
path = path.substr(RESOURCES_PREFIX.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove "data/" prefix if present
|
|
||||||
const std::string DATA_PREFIX = "data/";
|
|
||||||
if (path.starts_with(DATA_PREFIX)) {
|
|
||||||
path = path.substr(DATA_PREFIX.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if file should use resource pack
|
|
||||||
auto shouldUseResourcePack(const std::string& filepath) -> bool {
|
|
||||||
std::string path = filepath;
|
|
||||||
std::ranges::replace(path, '\\', '/');
|
|
||||||
|
|
||||||
// Don't use pack for most config files (except config/assets.yaml which is loaded
|
|
||||||
// directly via Loader::loadAssetsConfig() in release builds)
|
|
||||||
if (path.find("config/") != std::string::npos) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use pack for data files
|
// Check if pack is loaded
|
||||||
if (path.find("data/") != std::string::npos) {
|
auto isPackLoaded() -> bool {
|
||||||
return true;
|
if (!resource_system_initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Loader::get().isPackLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it looks like a data file (has common extensions)
|
|
||||||
if (path.find(".ogg") != std::string::npos || path.find(".wav") != std::string::npos ||
|
|
||||||
path.find(".gif") != std::string::npos || path.find(".png") != std::string::npos ||
|
|
||||||
path.find(".pal") != std::string::npos || path.find(".yaml") != std::string::npos ||
|
|
||||||
path.find(".txt") != std::string::npos || path.find(".glsl") != std::string::npos) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if pack is loaded
|
|
||||||
auto isPackLoaded() -> bool {
|
|
||||||
if (!resource_system_initialized) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Loader::get().isPackLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Resource::Helper
|
} // namespace Resource::Helper
|
||||||
|
|||||||
@@ -9,30 +9,30 @@
|
|||||||
|
|
||||||
namespace Resource::Helper {
|
namespace Resource::Helper {
|
||||||
|
|
||||||
// Initialize the resource system
|
// Initialize the resource system
|
||||||
// pack_file: Path to resources.pack
|
// pack_file: Path to resources.pack
|
||||||
// enable_fallback: Allow loading from filesystem if pack not available
|
// enable_fallback: Allow loading from filesystem if pack not available
|
||||||
auto initializeResourceSystem(const std::string& pack_file = "resources.pack",
|
auto initializeResourceSystem(const std::string& pack_file = "resources.pack",
|
||||||
bool enable_fallback = true) -> bool;
|
bool enable_fallback = true) -> bool;
|
||||||
|
|
||||||
// Shutdown the resource system
|
// Shutdown the resource system
|
||||||
void shutdownResourceSystem();
|
void shutdownResourceSystem();
|
||||||
|
|
||||||
// Load a file (tries pack first, then filesystem if fallback enabled)
|
// Load a file (tries pack first, then filesystem if fallback enabled)
|
||||||
auto loadFile(const std::string& filepath) -> std::vector<uint8_t>;
|
auto loadFile(const std::string& filepath) -> std::vector<uint8_t>;
|
||||||
|
|
||||||
// Check if a file exists
|
// Check if a file exists
|
||||||
auto fileExists(const std::string& filepath) -> bool;
|
auto fileExists(const std::string& filepath) -> bool;
|
||||||
|
|
||||||
// Convert an asset path to a pack path
|
// Convert an asset path to a pack path
|
||||||
// Example: "data/music/title.ogg" -> "music/title.ogg"
|
// Example: "data/music/title.ogg" -> "music/title.ogg"
|
||||||
auto getPackPath(const std::string& asset_path) -> std::string;
|
auto getPackPath(const std::string& asset_path) -> std::string;
|
||||||
|
|
||||||
// Check if a file should use the resource pack
|
// Check if a file should use the resource pack
|
||||||
// Returns false for config/ files (always from filesystem)
|
// Returns false for config/ files (always from filesystem)
|
||||||
auto shouldUseResourcePack(const std::string& filepath) -> bool;
|
auto shouldUseResourcePack(const std::string& filepath) -> bool;
|
||||||
|
|
||||||
// Check if pack is loaded
|
// Check if pack is loaded
|
||||||
auto isPackLoaded() -> bool;
|
auto isPackLoaded() -> bool;
|
||||||
|
|
||||||
} // namespace Resource::Helper
|
} // namespace Resource::Helper
|
||||||
|
|||||||
@@ -16,305 +16,305 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// Singleton
|
// Singleton
|
||||||
List* List::instance = nullptr;
|
List* List::instance = nullptr;
|
||||||
|
|
||||||
void List::init(const std::string& executable_path) {
|
void List::init(const std::string& executable_path) {
|
||||||
List::instance = new List(executable_path);
|
List::instance = new List(executable_path);
|
||||||
}
|
|
||||||
|
|
||||||
void List::destroy() {
|
|
||||||
delete List::instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto List::get() -> List* {
|
|
||||||
return List::instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Añade un elemento al mapa (función auxiliar)
|
|
||||||
void List::addToMap(const std::string& file_path, Type type, bool required, bool absolute) {
|
|
||||||
std::string full_path = absolute ? file_path : executable_path_ + file_path;
|
|
||||||
std::string filename = getFileName(full_path);
|
|
||||||
|
|
||||||
// Verificar si ya existe el archivo
|
|
||||||
if (file_list_.find(filename) != file_list_.end()) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Warning: Asset '%s' already exists, overwriting",
|
|
||||||
filename.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file_list_.emplace(filename, Item{std::move(full_path), type, required});
|
void List::destroy() {
|
||||||
}
|
delete List::instance;
|
||||||
|
|
||||||
// Añade un elemento a la lista
|
|
||||||
void List::add(const std::string& file_path, Type type, bool required, bool absolute) {
|
|
||||||
addToMap(file_path, type, required, absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga recursos desde un archivo de configuración con soporte para variables
|
|
||||||
void List::loadFromFile(const std::string& config_file_path, const std::string& prefix, const std::string& system_folder) {
|
|
||||||
std::ifstream file(config_file_path);
|
|
||||||
if (!file.is_open()) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Error: Cannot open config file: %s",
|
|
||||||
config_file_path.c_str());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read entire file into string
|
auto List::get() -> List* {
|
||||||
std::stringstream buffer;
|
return List::instance;
|
||||||
buffer << file.rdbuf();
|
}
|
||||||
file.close();
|
|
||||||
|
|
||||||
// Parse using loadFromString
|
// Añade un elemento al mapa (función auxiliar)
|
||||||
loadFromString(buffer.str(), prefix, system_folder);
|
void List::addToMap(const std::string& file_path, Type type, bool required, bool absolute) {
|
||||||
}
|
std::string full_path = absolute ? file_path : executable_path_ + file_path;
|
||||||
|
std::string filename = getFileName(full_path);
|
||||||
|
|
||||||
// Carga recursos desde un string de configuración (para release con pack)
|
// Verificar si ya existe el archivo
|
||||||
void List::loadFromString(const std::string& config_content, const std::string& prefix, const std::string& system_folder) {
|
if (file_list_.find(filename) != file_list_.end()) {
|
||||||
try {
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
// Parsear YAML
|
"Warning: Asset '%s' already exists, overwriting",
|
||||||
auto yaml = fkyaml::node::deserialize(config_content);
|
filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// Verificar estructura básica
|
file_list_.emplace(filename, Item{std::move(full_path), type, required});
|
||||||
if (!yaml.contains("assets")) {
|
}
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid assets.yaml format - missing 'assets' key");
|
|
||||||
|
// Añade un elemento a la lista
|
||||||
|
void List::add(const std::string& file_path, Type type, bool required, bool absolute) {
|
||||||
|
addToMap(file_path, type, required, absolute);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga recursos desde un archivo de configuración con soporte para variables
|
||||||
|
void List::loadFromFile(const std::string& config_file_path, const std::string& prefix, const std::string& system_folder) {
|
||||||
|
std::ifstream file(config_file_path);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Error: Cannot open config file: %s",
|
||||||
|
config_file_path.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& assets = yaml["assets"];
|
// Read entire file into string
|
||||||
|
std::stringstream buffer;
|
||||||
// Iterar sobre cada categoría (fonts, palettes, etc.)
|
buffer << file.rdbuf();
|
||||||
for (auto it = assets.begin(); it != assets.end(); ++it) {
|
|
||||||
const std::string& category = it.key().get_value<std::string>();
|
|
||||||
const auto& category_assets = it.value();
|
|
||||||
|
|
||||||
// Verificar que es un array
|
|
||||||
if (!category_assets.is_sequence()) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Warning: Category '%s' is not a sequence, skipping",
|
|
||||||
category.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Procesar cada asset en la categoría
|
|
||||||
for (const auto& asset : category_assets) {
|
|
||||||
try {
|
|
||||||
// Verificar campos obligatorios
|
|
||||||
if (!asset.contains("type") || !asset.contains("path")) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Warning: Asset in category '%s' missing 'type' or 'path', skipping",
|
|
||||||
category.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extraer campos
|
|
||||||
auto type_str = asset["type"].get_value<std::string>();
|
|
||||||
auto path = asset["path"].get_value<std::string>();
|
|
||||||
|
|
||||||
// Valores por defecto
|
|
||||||
bool required = true;
|
|
||||||
bool absolute = false;
|
|
||||||
|
|
||||||
// Campos opcionales
|
|
||||||
if (asset.contains("required")) {
|
|
||||||
required = asset["required"].get_value<bool>();
|
|
||||||
}
|
|
||||||
if (asset.contains("absolute")) {
|
|
||||||
absolute = asset["absolute"].get_value<bool>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reemplazar variables en la ruta
|
|
||||||
path = replaceVariables(path, prefix, system_folder);
|
|
||||||
|
|
||||||
// Parsear el tipo de asset
|
|
||||||
Type type = parseAssetType(type_str);
|
|
||||||
|
|
||||||
// Añadir al mapa
|
|
||||||
addToMap(path, type, required, absolute);
|
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Error parsing asset in category '%s': %s",
|
|
||||||
category.c_str(),
|
|
||||||
e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Loaded " << file_list_.size() << " assets from YAML config" << '\n';
|
|
||||||
|
|
||||||
} catch (const fkyaml::exception& e) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"YAML parsing error: %s",
|
|
||||||
e.what());
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Error loading assets: %s",
|
|
||||||
e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Devuelve la ruta completa a un fichero (búsqueda O(1))
|
|
||||||
auto List::get(const std::string& filename) const -> std::string {
|
|
||||||
auto it = file_list_.find(filename);
|
|
||||||
if (it != file_list_.end()) {
|
|
||||||
return it->second.file;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", filename.c_str());
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carga datos del archivo
|
|
||||||
auto List::loadData(const std::string& filename) const -> std::vector<uint8_t> {
|
|
||||||
auto it = file_list_.find(filename);
|
|
||||||
if (it != file_list_.end()) {
|
|
||||||
std::ifstream file(it->second.file, std::ios::binary);
|
|
||||||
if (!file.is_open()) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Warning: Could not open file %s for data loading",
|
|
||||||
filename.c_str());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener tamaño del archivo
|
|
||||||
file.seekg(0, std::ios::end);
|
|
||||||
size_t size = file.tellg();
|
|
||||||
file.seekg(0, std::ios::beg);
|
|
||||||
|
|
||||||
// Leer datos
|
|
||||||
std::vector<uint8_t> data(size);
|
|
||||||
file.read(reinterpret_cast<char*>(data.data()), size);
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
return data;
|
// Parse using loadFromString
|
||||||
|
loadFromString(buffer.str(), prefix, system_folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
|
// Carga recursos desde un string de configuración (para release con pack)
|
||||||
return {};
|
void List::loadFromString(const std::string& config_content, const std::string& prefix, const std::string& system_folder) {
|
||||||
}
|
try {
|
||||||
|
// Parsear YAML
|
||||||
|
auto yaml = fkyaml::node::deserialize(config_content);
|
||||||
|
|
||||||
// Verifica si un recurso existe
|
// Verificar estructura básica
|
||||||
auto List::exists(const std::string& filename) const -> bool {
|
if (!yaml.contains("assets")) {
|
||||||
return file_list_.find(filename) != file_list_.end();
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Invalid assets.yaml format - missing 'assets' key");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Parsea string a Type
|
const auto& assets = yaml["assets"];
|
||||||
auto List::parseAssetType(const std::string& type_str) -> Type {
|
|
||||||
if (type_str == "DATA") {
|
|
||||||
return Type::DATA;
|
|
||||||
}
|
|
||||||
if (type_str == "BITMAP") {
|
|
||||||
return Type::BITMAP;
|
|
||||||
}
|
|
||||||
if (type_str == "ANIMATION") {
|
|
||||||
return Type::ANIMATION;
|
|
||||||
}
|
|
||||||
if (type_str == "MUSIC") {
|
|
||||||
return Type::MUSIC;
|
|
||||||
}
|
|
||||||
if (type_str == "SOUND") {
|
|
||||||
return Type::SOUND;
|
|
||||||
}
|
|
||||||
if (type_str == "FONT") {
|
|
||||||
return Type::FONT;
|
|
||||||
}
|
|
||||||
if (type_str == "ROOM") {
|
|
||||||
return Type::ROOM;
|
|
||||||
}
|
|
||||||
if (type_str == "TILEMAP") {
|
|
||||||
// TILEMAP está obsoleto, ahora todo es ROOM (.yaml unificado)
|
|
||||||
return Type::ROOM;
|
|
||||||
}
|
|
||||||
if (type_str == "PALETTE") {
|
|
||||||
return Type::PALETTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::runtime_error("Unknown asset type: " + type_str);
|
// Iterar sobre cada categoría (fonts, palettes, etc.)
|
||||||
}
|
for (auto it = assets.begin(); it != assets.end(); ++it) {
|
||||||
|
const std::string& category = it.key().get_value<std::string>();
|
||||||
|
const auto& category_assets = it.value();
|
||||||
|
|
||||||
// Devuelve el nombre del tipo de recurso
|
// Verificar que es un array
|
||||||
auto List::getTypeName(Type type) -> std::string {
|
if (!category_assets.is_sequence()) {
|
||||||
switch (type) {
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
case Type::DATA:
|
"Warning: Category '%s' is not a sequence, skipping",
|
||||||
return "DATA";
|
category.c_str());
|
||||||
case Type::BITMAP:
|
continue;
|
||||||
return "BITMAP";
|
}
|
||||||
case Type::ANIMATION:
|
|
||||||
return "ANIMATION";
|
|
||||||
case Type::MUSIC:
|
|
||||||
return "MUSIC";
|
|
||||||
case Type::SOUND:
|
|
||||||
return "SOUND";
|
|
||||||
case Type::FONT:
|
|
||||||
return "FONT";
|
|
||||||
case Type::ROOM:
|
|
||||||
return "ROOM";
|
|
||||||
case Type::PALETTE:
|
|
||||||
return "PALETTE";
|
|
||||||
default:
|
|
||||||
return "ERROR";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Devuelve la lista de recursos de un tipo
|
// Procesar cada asset en la categoría
|
||||||
auto List::getListByType(Type type) const -> std::vector<std::string> {
|
for (const auto& asset : category_assets) {
|
||||||
std::vector<std::string> list;
|
try {
|
||||||
|
// Verificar campos obligatorios
|
||||||
|
if (!asset.contains("type") || !asset.contains("path")) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Warning: Asset in category '%s' missing 'type' or 'path', skipping",
|
||||||
|
category.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& [filename, item] : file_list_) {
|
// Extraer campos
|
||||||
if (item.type == type) {
|
auto type_str = asset["type"].get_value<std::string>();
|
||||||
list.push_back(item.file);
|
auto path = asset["path"].get_value<std::string>();
|
||||||
|
|
||||||
|
// Valores por defecto
|
||||||
|
bool required = true;
|
||||||
|
bool absolute = false;
|
||||||
|
|
||||||
|
// Campos opcionales
|
||||||
|
if (asset.contains("required")) {
|
||||||
|
required = asset["required"].get_value<bool>();
|
||||||
|
}
|
||||||
|
if (asset.contains("absolute")) {
|
||||||
|
absolute = asset["absolute"].get_value<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reemplazar variables en la ruta
|
||||||
|
path = replaceVariables(path, prefix, system_folder);
|
||||||
|
|
||||||
|
// Parsear el tipo de asset
|
||||||
|
Type type = parseAssetType(type_str);
|
||||||
|
|
||||||
|
// Añadir al mapa
|
||||||
|
addToMap(path, type, required, absolute);
|
||||||
|
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Error parsing asset in category '%s': %s",
|
||||||
|
category.c_str(),
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Loaded " << file_list_.size() << " assets from YAML config" << '\n';
|
||||||
|
|
||||||
|
} catch (const fkyaml::exception& e) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"YAML parsing error: %s",
|
||||||
|
e.what());
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Error loading assets: %s",
|
||||||
|
e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ordenar alfabéticamente para garantizar orden consistente
|
// Devuelve la ruta completa a un fichero (búsqueda O(1))
|
||||||
std::ranges::sort(list);
|
auto List::get(const std::string& filename) const -> std::string {
|
||||||
|
auto it = file_list_.find(filename);
|
||||||
|
if (it != file_list_.end()) {
|
||||||
|
return it->second.file;
|
||||||
|
}
|
||||||
|
|
||||||
return list;
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", filename.c_str());
|
||||||
}
|
return "";
|
||||||
|
|
||||||
// Reemplaza variables en las rutas
|
|
||||||
auto List::replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string {
|
|
||||||
std::string result = path;
|
|
||||||
|
|
||||||
// Reemplazar ${PREFIX}
|
|
||||||
size_t pos = 0;
|
|
||||||
while ((pos = result.find("${PREFIX}", pos)) != std::string::npos) {
|
|
||||||
result.replace(pos, 9, prefix); // 9 = longitud de "${PREFIX}"
|
|
||||||
pos += prefix.length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reemplazar ${SYSTEM_FOLDER}
|
// Carga datos del archivo
|
||||||
pos = 0;
|
auto List::loadData(const std::string& filename) const -> std::vector<uint8_t> {
|
||||||
while ((pos = result.find("${SYSTEM_FOLDER}", pos)) != std::string::npos) {
|
auto it = file_list_.find(filename);
|
||||||
result.replace(pos, 16, system_folder); // 16 = longitud de "${SYSTEM_FOLDER}"
|
if (it != file_list_.end()) {
|
||||||
pos += system_folder.length();
|
std::ifstream file(it->second.file, std::ios::binary);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Warning: Could not open file %s for data loading",
|
||||||
|
filename.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener tamaño del archivo
|
||||||
|
file.seekg(0, std::ios::end);
|
||||||
|
size_t size = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
// Leer datos
|
||||||
|
std::vector<uint8_t> data(size);
|
||||||
|
file.read(reinterpret_cast<char*>(data.data()), size);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
// Verifica si un recurso existe
|
||||||
}
|
auto List::exists(const std::string& filename) const -> bool {
|
||||||
|
return file_list_.find(filename) != file_list_.end();
|
||||||
// Parsea las opciones de una línea de configuración
|
|
||||||
auto List::parseOptions(const std::string& options, bool& required, bool& absolute) -> void {
|
|
||||||
if (options.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::istringstream iss(options);
|
// Parsea string a Type
|
||||||
std::string option;
|
auto List::parseAssetType(const std::string& type_str) -> Type {
|
||||||
|
if (type_str == "DATA") {
|
||||||
|
return Type::DATA;
|
||||||
|
}
|
||||||
|
if (type_str == "BITMAP") {
|
||||||
|
return Type::BITMAP;
|
||||||
|
}
|
||||||
|
if (type_str == "ANIMATION") {
|
||||||
|
return Type::ANIMATION;
|
||||||
|
}
|
||||||
|
if (type_str == "MUSIC") {
|
||||||
|
return Type::MUSIC;
|
||||||
|
}
|
||||||
|
if (type_str == "SOUND") {
|
||||||
|
return Type::SOUND;
|
||||||
|
}
|
||||||
|
if (type_str == "FONT") {
|
||||||
|
return Type::FONT;
|
||||||
|
}
|
||||||
|
if (type_str == "ROOM") {
|
||||||
|
return Type::ROOM;
|
||||||
|
}
|
||||||
|
if (type_str == "TILEMAP") {
|
||||||
|
// TILEMAP está obsoleto, ahora todo es ROOM (.yaml unificado)
|
||||||
|
return Type::ROOM;
|
||||||
|
}
|
||||||
|
if (type_str == "PALETTE") {
|
||||||
|
return Type::PALETTE;
|
||||||
|
}
|
||||||
|
|
||||||
while (std::getline(iss, option, ',')) {
|
throw std::runtime_error("Unknown asset type: " + type_str);
|
||||||
// Eliminar espacios
|
}
|
||||||
option.erase(0, option.find_first_not_of(" \t"));
|
|
||||||
option.erase(option.find_last_not_of(" \t") + 1);
|
|
||||||
|
|
||||||
if (option == "optional") {
|
// Devuelve el nombre del tipo de recurso
|
||||||
required = false;
|
auto List::getTypeName(Type type) -> std::string {
|
||||||
} else if (option == "absolute") {
|
switch (type) {
|
||||||
absolute = true;
|
case Type::DATA:
|
||||||
|
return "DATA";
|
||||||
|
case Type::BITMAP:
|
||||||
|
return "BITMAP";
|
||||||
|
case Type::ANIMATION:
|
||||||
|
return "ANIMATION";
|
||||||
|
case Type::MUSIC:
|
||||||
|
return "MUSIC";
|
||||||
|
case Type::SOUND:
|
||||||
|
return "SOUND";
|
||||||
|
case Type::FONT:
|
||||||
|
return "FONT";
|
||||||
|
case Type::ROOM:
|
||||||
|
return "ROOM";
|
||||||
|
case Type::PALETTE:
|
||||||
|
return "PALETTE";
|
||||||
|
default:
|
||||||
|
return "ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Devuelve la lista de recursos de un tipo
|
||||||
|
auto List::getListByType(Type type) const -> std::vector<std::string> {
|
||||||
|
std::vector<std::string> list;
|
||||||
|
|
||||||
|
for (const auto& [filename, item] : file_list_) {
|
||||||
|
if (item.type == type) {
|
||||||
|
list.push_back(item.file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordenar alfabéticamente para garantizar orden consistente
|
||||||
|
std::ranges::sort(list);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reemplaza variables en las rutas
|
||||||
|
auto List::replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string {
|
||||||
|
std::string result = path;
|
||||||
|
|
||||||
|
// Reemplazar ${PREFIX}
|
||||||
|
size_t pos = 0;
|
||||||
|
while ((pos = result.find("${PREFIX}", pos)) != std::string::npos) {
|
||||||
|
result.replace(pos, 9, prefix); // 9 = longitud de "${PREFIX}"
|
||||||
|
pos += prefix.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reemplazar ${SYSTEM_FOLDER}
|
||||||
|
pos = 0;
|
||||||
|
while ((pos = result.find("${SYSTEM_FOLDER}", pos)) != std::string::npos) {
|
||||||
|
result.replace(pos, 16, system_folder); // 16 = longitud de "${SYSTEM_FOLDER}"
|
||||||
|
pos += system_folder.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsea las opciones de una línea de configuración
|
||||||
|
auto List::parseOptions(const std::string& options, bool& required, bool& absolute) -> void {
|
||||||
|
if (options.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream iss(options);
|
||||||
|
std::string option;
|
||||||
|
|
||||||
|
while (std::getline(iss, option, ',')) {
|
||||||
|
// Eliminar espacios
|
||||||
|
option.erase(0, option.find_first_not_of(" \t"));
|
||||||
|
option.erase(option.find_last_not_of(" \t") + 1);
|
||||||
|
|
||||||
|
if (option == "optional") {
|
||||||
|
required = false;
|
||||||
|
} else if (option == "absolute") {
|
||||||
|
absolute = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// --- Clase List: gestor optimizado de recursos (singleton) ---
|
// --- Clase List: gestor optimizado de recursos (singleton) ---
|
||||||
class List {
|
class List {
|
||||||
public:
|
public:
|
||||||
// --- Enums ---
|
// --- Enums ---
|
||||||
enum class Type : int {
|
enum class Type : int {
|
||||||
DATA, // Datos
|
DATA, // Datos
|
||||||
@@ -40,17 +40,17 @@ class List {
|
|||||||
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
|
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
|
||||||
[[nodiscard]] auto exists(const std::string& filename) const -> bool; // Verifica si un asset existe
|
[[nodiscard]] auto exists(const std::string& filename) const -> bool; // Verifica si un asset existe
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Estructuras privadas ---
|
// --- Estructuras privadas ---
|
||||||
struct Item {
|
struct Item {
|
||||||
std::string file; // Ruta completa del archivo
|
std::string file; // Ruta completa del archivo
|
||||||
Type type; // Tipo de recurso
|
Type type; // Tipo de recurso
|
||||||
bool required; // Indica si el archivo es obligatorio
|
bool required; // Indica si el archivo es obligatorio
|
||||||
|
|
||||||
Item(std::string path, Type asset_type, bool is_required)
|
Item(std::string path, Type asset_type, bool is_required)
|
||||||
: file(std::move(path)),
|
: file(std::move(path)),
|
||||||
type(asset_type),
|
type(asset_type),
|
||||||
required(is_required) {}
|
required(is_required) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Variables internas ---
|
// --- Variables internas ---
|
||||||
@@ -71,6 +71,6 @@ class List {
|
|||||||
|
|
||||||
// --- Instancia singleton ---
|
// --- Instancia singleton ---
|
||||||
static List* instance; // Instancia única de List
|
static List* instance; // Instancia única de List
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -9,191 +9,191 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// Get singleton instance
|
// Get singleton instance
|
||||||
auto Loader::get() -> Loader& {
|
auto Loader::get() -> Loader& {
|
||||||
static Loader instance_;
|
static Loader instance_;
|
||||||
return instance_;
|
return instance_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize with a pack file
|
// Initialize with a pack file
|
||||||
auto Loader::initialize(const std::string& pack_file, bool enable_fallback)
|
auto Loader::initialize(const std::string& pack_file, bool enable_fallback)
|
||||||
-> bool {
|
-> bool {
|
||||||
if (initialized_) {
|
if (initialized_) {
|
||||||
std::cout << "Loader: Already initialized\n";
|
std::cout << "Loader: Already initialized\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback_to_files_ = enable_fallback;
|
||||||
|
|
||||||
|
// Try to load the pack file
|
||||||
|
if (!pack_file.empty() && fileExistsOnFilesystem(pack_file)) {
|
||||||
|
std::cout << "Loader: Loading pack file: " << pack_file << '\n';
|
||||||
|
resource_pack_ = std::make_unique<Pack>();
|
||||||
|
if (resource_pack_->loadPack(pack_file)) {
|
||||||
|
std::cout << "Loader: Pack loaded successfully\n";
|
||||||
|
initialized_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::cerr << "Loader: Failed to load pack file\n";
|
||||||
|
resource_pack_.reset();
|
||||||
|
} else {
|
||||||
|
std::cout << "Loader: Pack file not found: " << pack_file << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If pack loading failed and fallback is disabled, fail
|
||||||
|
if (!fallback_to_files_) {
|
||||||
|
std::cerr << "Loader: Pack required but not found (fallback disabled)\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, fallback to filesystem
|
||||||
|
std::cout << "Loader: Using filesystem fallback\n";
|
||||||
|
initialized_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback_to_files_ = enable_fallback;
|
// Load a resource
|
||||||
|
auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
|
||||||
// Try to load the pack file
|
if (!initialized_) {
|
||||||
if (!pack_file.empty() && fileExistsOnFilesystem(pack_file)) {
|
std::cerr << "Loader: Not initialized\n";
|
||||||
std::cout << "Loader: Loading pack file: " << pack_file << '\n';
|
return {};
|
||||||
resource_pack_ = std::make_unique<Pack>();
|
|
||||||
if (resource_pack_->loadPack(pack_file)) {
|
|
||||||
std::cout << "Loader: Pack loaded successfully\n";
|
|
||||||
initialized_ = true;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
std::cerr << "Loader: Failed to load pack file\n";
|
|
||||||
resource_pack_.reset();
|
|
||||||
} else {
|
|
||||||
std::cout << "Loader: Pack file not found: " << pack_file << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If pack loading failed and fallback is disabled, fail
|
// Try pack first if available
|
||||||
if (!fallback_to_files_) {
|
if (resource_pack_ && resource_pack_->isLoaded()) {
|
||||||
std::cerr << "Loader: Pack required but not found (fallback disabled)\n";
|
if (resource_pack_->hasResource(filename)) {
|
||||||
return false;
|
auto data = resource_pack_->getResource(filename);
|
||||||
}
|
if (!data.empty()) {
|
||||||
|
return data;
|
||||||
// Otherwise, fallback to filesystem
|
}
|
||||||
std::cout << "Loader: Using filesystem fallback\n";
|
std::cerr << "Loader: Failed to extract from pack: " << filename
|
||||||
initialized_ = true;
|
<< '\n';
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load a resource
|
|
||||||
auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
|
|
||||||
if (!initialized_) {
|
|
||||||
std::cerr << "Loader: Not initialized\n";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try pack first if available
|
|
||||||
if (resource_pack_ && resource_pack_->isLoaded()) {
|
|
||||||
if (resource_pack_->hasResource(filename)) {
|
|
||||||
auto data = resource_pack_->getResource(filename);
|
|
||||||
if (!data.empty()) {
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
std::cerr << "Loader: Failed to extract from pack: " << filename
|
|
||||||
<< '\n';
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to filesystem if enabled
|
// Fallback to filesystem if enabled
|
||||||
if (fallback_to_files_) {
|
if (fallback_to_files_) {
|
||||||
return loadFromFilesystem(filename);
|
return loadFromFilesystem(filename);
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "Loader: Resource not found: " << filename << '\n';
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a resource exists
|
|
||||||
auto Loader::resourceExists(const std::string& filename) -> bool {
|
|
||||||
if (!initialized_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check pack first
|
|
||||||
if (resource_pack_ && resource_pack_->isLoaded()) {
|
|
||||||
if (resource_pack_->hasResource(filename)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check filesystem if fallback enabled
|
std::cerr << "Loader: Resource not found: " << filename << '\n';
|
||||||
if (fallback_to_files_) {
|
|
||||||
return fileExistsOnFilesystem(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if pack is loaded
|
|
||||||
auto Loader::isPackLoaded() const -> bool {
|
|
||||||
return resource_pack_ && resource_pack_->isLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get pack statistics
|
|
||||||
auto Loader::getPackResourceCount() const -> size_t {
|
|
||||||
if (resource_pack_ && resource_pack_->isLoaded()) {
|
|
||||||
return resource_pack_->getResourceCount();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
void Loader::shutdown() {
|
|
||||||
resource_pack_.reset();
|
|
||||||
initialized_ = false;
|
|
||||||
std::cout << "Loader: Shutdown complete\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load from filesystem
|
|
||||||
auto Loader::loadFromFilesystem(const std::string& filepath)
|
|
||||||
-> std::vector<uint8_t> {
|
|
||||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
|
||||||
if (!file) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize file_size = file.tellg();
|
// Check if a resource exists
|
||||||
file.seekg(0, std::ios::beg);
|
auto Loader::resourceExists(const std::string& filename) -> bool {
|
||||||
|
if (!initialized_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> data(file_size);
|
// Check pack first
|
||||||
if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
|
if (resource_pack_ && resource_pack_->isLoaded()) {
|
||||||
std::cerr << "Loader: Failed to read file: " << filepath << '\n';
|
if (resource_pack_->hasResource(filename)) {
|
||||||
return {};
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
// Check filesystem if fallback enabled
|
||||||
}
|
if (fallback_to_files_) {
|
||||||
|
return fileExistsOnFilesystem(filename);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if file exists on filesystem
|
|
||||||
auto Loader::fileExistsOnFilesystem(const std::string& filepath) -> bool {
|
|
||||||
return std::filesystem::exists(filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate pack integrity
|
|
||||||
auto Loader::validatePack() const -> bool {
|
|
||||||
if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
|
|
||||||
std::cerr << "Loader: Cannot validate - pack not loaded\n";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate pack checksum
|
// Check if pack is loaded
|
||||||
uint32_t checksum = resource_pack_->calculatePackChecksum();
|
auto Loader::isPackLoaded() const -> bool {
|
||||||
|
return resource_pack_ && resource_pack_->isLoaded();
|
||||||
if (checksum == 0) {
|
|
||||||
std::cerr << "Loader: Pack checksum is zero (invalid)\n";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Loader: Pack checksum: 0x" << std::hex << checksum << std::dec
|
// Get pack statistics
|
||||||
<< '\n';
|
auto Loader::getPackResourceCount() const -> size_t {
|
||||||
std::cout << "Loader: Pack validation successful\n";
|
if (resource_pack_ && resource_pack_->isLoaded()) {
|
||||||
return true;
|
return resource_pack_->getResourceCount();
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
// Load assets.yaml from pack
|
|
||||||
auto Loader::loadAssetsConfig() const -> std::string {
|
|
||||||
if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
|
|
||||||
std::cerr << "Loader: Cannot load assets config - pack not loaded\n";
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load config/assets.yaml from pack
|
// Cleanup
|
||||||
std::string config_path = "config/assets.yaml";
|
void Loader::shutdown() {
|
||||||
|
resource_pack_.reset();
|
||||||
if (!resource_pack_->hasResource(config_path)) {
|
initialized_ = false;
|
||||||
std::cerr << "Loader: assets.yaml not found in pack: " << config_path << '\n';
|
std::cout << "Loader: Shutdown complete\n";
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = resource_pack_->getResource(config_path);
|
// Load from filesystem
|
||||||
if (data.empty()) {
|
auto Loader::loadFromFilesystem(const std::string& filepath)
|
||||||
std::cerr << "Loader: Failed to load assets.yaml from pack\n";
|
-> std::vector<uint8_t> {
|
||||||
return "";
|
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize file_size = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
std::vector<uint8_t> data(file_size);
|
||||||
|
if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
|
||||||
|
std::cerr << "Loader: Failed to read file: " << filepath << '\n';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert bytes to string
|
// Check if file exists on filesystem
|
||||||
std::string config_content(data.begin(), data.end());
|
auto Loader::fileExistsOnFilesystem(const std::string& filepath) -> bool {
|
||||||
std::cout << "Loader: Loaded assets.yaml from pack (" << data.size()
|
return std::filesystem::exists(filepath);
|
||||||
<< " bytes)\n";
|
}
|
||||||
|
|
||||||
return config_content;
|
// Validate pack integrity
|
||||||
}
|
auto Loader::validatePack() const -> bool {
|
||||||
|
if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
|
||||||
|
std::cerr << "Loader: Cannot validate - pack not loaded\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate pack checksum
|
||||||
|
uint32_t checksum = resource_pack_->calculatePackChecksum();
|
||||||
|
|
||||||
|
if (checksum == 0) {
|
||||||
|
std::cerr << "Loader: Pack checksum is zero (invalid)\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Loader: Pack checksum: 0x" << std::hex << checksum << std::dec
|
||||||
|
<< '\n';
|
||||||
|
std::cout << "Loader: Pack validation successful\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load assets.yaml from pack
|
||||||
|
auto Loader::loadAssetsConfig() const -> std::string {
|
||||||
|
if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
|
||||||
|
std::cerr << "Loader: Cannot load assets config - pack not loaded\n";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load config/assets.yaml from pack
|
||||||
|
std::string config_path = "config/assets.yaml";
|
||||||
|
|
||||||
|
if (!resource_pack_->hasResource(config_path)) {
|
||||||
|
std::cerr << "Loader: assets.yaml not found in pack: " << config_path << '\n';
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = resource_pack_->getResource(config_path);
|
||||||
|
if (data.empty()) {
|
||||||
|
std::cerr << "Loader: Failed to load assets.yaml from pack\n";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert bytes to string
|
||||||
|
std::string config_content(data.begin(), data.end());
|
||||||
|
std::cout << "Loader: Loaded assets.yaml from pack (" << data.size()
|
||||||
|
<< " bytes)\n";
|
||||||
|
|
||||||
|
return config_content;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// Singleton class for loading resources from pack or filesystem
|
// Singleton class for loading resources from pack or filesystem
|
||||||
class Loader {
|
class Loader {
|
||||||
public:
|
public:
|
||||||
static auto get() -> Loader&; // Singleton instance access
|
static auto get() -> Loader&; // Singleton instance access
|
||||||
|
|
||||||
auto initialize(const std::string& pack_file, bool enable_fallback = true) -> bool; // Initialize loader with pack file
|
auto initialize(const std::string& pack_file, bool enable_fallback = true) -> bool; // Initialize loader with pack file
|
||||||
@@ -33,7 +33,7 @@ class Loader {
|
|||||||
Loader(Loader&&) = delete;
|
Loader(Loader&&) = delete;
|
||||||
auto operator=(Loader&&) -> Loader& = delete;
|
auto operator=(Loader&&) -> Loader& = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Loader() = default;
|
Loader() = default;
|
||||||
~Loader() = default;
|
~Loader() = default;
|
||||||
|
|
||||||
@@ -43,6 +43,6 @@ class Loader {
|
|||||||
std::unique_ptr<Pack> resource_pack_; // Member variables
|
std::unique_ptr<Pack> resource_pack_; // Member variables
|
||||||
bool fallback_to_files_{true};
|
bool fallback_to_files_{true};
|
||||||
bool initialized_{false};
|
bool initialized_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -12,292 +12,292 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// Calculate CRC32 checksum for data verification
|
// Calculate CRC32 checksum for data verification
|
||||||
auto Pack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t {
|
auto Pack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t {
|
||||||
uint32_t checksum = 0x12345678;
|
uint32_t checksum = 0x12345678;
|
||||||
for (unsigned char byte : data) {
|
for (unsigned char byte : data) {
|
||||||
checksum = ((checksum << 5) + checksum) + byte;
|
checksum = ((checksum << 5) + checksum) + byte;
|
||||||
}
|
}
|
||||||
return checksum;
|
return checksum;
|
||||||
}
|
|
||||||
|
|
||||||
// XOR encryption (symmetric - same function for encrypt/decrypt)
|
|
||||||
void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
|
|
||||||
if (key.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < data.size(); ++i) {
|
|
||||||
data[i] ^= key[i % key.length()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pack::decryptData(std::vector<uint8_t>& data, const std::string& key) {
|
|
||||||
// XOR is symmetric
|
|
||||||
encryptData(data, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read entire file into memory
|
|
||||||
auto Pack::readFile(const std::string& filepath) -> std::vector<uint8_t> {
|
|
||||||
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
|
||||||
if (!file) {
|
|
||||||
std::cerr << "ResourcePack: Failed to open file: " << filepath << '\n';
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::streamsize file_size = file.tellg();
|
// XOR encryption (symmetric - same function for encrypt/decrypt)
|
||||||
file.seekg(0, std::ios::beg);
|
void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||||
|
if (key.empty()) {
|
||||||
std::vector<uint8_t> data(file_size);
|
return;
|
||||||
if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
|
}
|
||||||
std::cerr << "ResourcePack: Failed to read file: " << filepath << '\n';
|
for (size_t i = 0; i < data.size(); ++i) {
|
||||||
return {};
|
data[i] ^= key[i % key.length()];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
void Pack::decryptData(std::vector<uint8_t>& data, const std::string& key) {
|
||||||
}
|
// XOR is symmetric
|
||||||
|
encryptData(data, key);
|
||||||
// Add a single file to the pack
|
|
||||||
auto Pack::addFile(const std::string& filepath, const std::string& pack_name)
|
|
||||||
-> bool {
|
|
||||||
auto file_data = readFile(filepath);
|
|
||||||
if (file_data.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceEntry entry{
|
// Read entire file into memory
|
||||||
.filename = pack_name,
|
auto Pack::readFile(const std::string& filepath) -> std::vector<uint8_t> {
|
||||||
.offset = data_.size(),
|
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||||
.size = file_data.size(),
|
if (!file) {
|
||||||
.checksum = calculateChecksum(file_data)};
|
std::cerr << "ResourcePack: Failed to open file: " << filepath << '\n';
|
||||||
|
return {};
|
||||||
// Append file data to the data block
|
|
||||||
data_.insert(data_.end(), file_data.begin(), file_data.end());
|
|
||||||
|
|
||||||
resources_[pack_name] = entry;
|
|
||||||
|
|
||||||
std::cout << "Added: " << pack_name << " (" << file_data.size() << " bytes)\n";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all files from a directory recursively
|
|
||||||
auto Pack::addDirectory(const std::string& dir_path,
|
|
||||||
const std::string& base_path) -> bool {
|
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
if (!fs::exists(dir_path) || !fs::is_directory(dir_path)) {
|
|
||||||
std::cerr << "ResourcePack: Directory not found: " << dir_path << '\n';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string current_base = base_path.empty() ? "" : base_path + "/";
|
|
||||||
|
|
||||||
for (const auto& entry : fs::recursive_directory_iterator(dir_path)) {
|
|
||||||
if (!entry.is_regular_file()) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string full_path = entry.path().string();
|
std::streamsize file_size = file.tellg();
|
||||||
std::string relative_path = entry.path().lexically_relative(dir_path).string();
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
// Convert backslashes to forward slashes (Windows compatibility)
|
std::vector<uint8_t> data(file_size);
|
||||||
std::ranges::replace(relative_path, '\\', '/');
|
if (!file.read(reinterpret_cast<char*>(data.data()), file_size)) {
|
||||||
|
std::cerr << "ResourcePack: Failed to read file: " << filepath << '\n';
|
||||||
// Skip development files
|
return {};
|
||||||
if (relative_path.find(".world") != std::string::npos ||
|
|
||||||
relative_path.find(".tsx") != std::string::npos) {
|
|
||||||
std::cout << "Skipping development file: " << relative_path << '\n';
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string pack_name = current_base + relative_path;
|
return data;
|
||||||
addFile(full_path, pack_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// Add a single file to the pack
|
||||||
}
|
auto Pack::addFile(const std::string& filepath, const std::string& pack_name)
|
||||||
|
-> bool {
|
||||||
|
auto file_data = readFile(filepath);
|
||||||
|
if (file_data.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Save the pack to a file
|
ResourceEntry entry{
|
||||||
auto Pack::savePack(const std::string& pack_file) -> bool {
|
.filename = pack_name,
|
||||||
std::ofstream file(pack_file, std::ios::binary);
|
.offset = data_.size(),
|
||||||
if (!file) {
|
.size = file_data.size(),
|
||||||
std::cerr << "ResourcePack: Failed to create pack file: " << pack_file << '\n';
|
.checksum = calculateChecksum(file_data)};
|
||||||
return false;
|
|
||||||
|
// Append file data to the data block
|
||||||
|
data_.insert(data_.end(), file_data.begin(), file_data.end());
|
||||||
|
|
||||||
|
resources_[pack_name] = entry;
|
||||||
|
|
||||||
|
std::cout << "Added: " << pack_name << " (" << file_data.size() << " bytes)\n";
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write header
|
// Add all files from a directory recursively
|
||||||
file.write(MAGIC_HEADER.data(), MAGIC_HEADER.size());
|
auto Pack::addDirectory(const std::string& dir_path,
|
||||||
file.write(reinterpret_cast<const char*>(&VERSION), sizeof(VERSION));
|
const std::string& base_path) -> bool {
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
// Write resource count
|
if (!fs::exists(dir_path) || !fs::is_directory(dir_path)) {
|
||||||
auto resource_count = static_cast<uint32_t>(resources_.size());
|
std::cerr << "ResourcePack: Directory not found: " << dir_path << '\n';
|
||||||
file.write(reinterpret_cast<const char*>(&resource_count), sizeof(resource_count));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Write resource entries
|
std::string current_base = base_path.empty() ? "" : base_path + "/";
|
||||||
for (const auto& [name, entry] : resources_) {
|
|
||||||
// Write filename length and name
|
|
||||||
auto name_len = static_cast<uint32_t>(entry.filename.length());
|
|
||||||
file.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len));
|
|
||||||
file.write(entry.filename.c_str(), name_len);
|
|
||||||
|
|
||||||
// Write offset, size, checksum
|
for (const auto& entry : fs::recursive_directory_iterator(dir_path)) {
|
||||||
file.write(reinterpret_cast<const char*>(&entry.offset), sizeof(entry.offset));
|
if (!entry.is_regular_file()) {
|
||||||
file.write(reinterpret_cast<const char*>(&entry.size), sizeof(entry.size));
|
continue;
|
||||||
file.write(reinterpret_cast<const char*>(&entry.checksum), sizeof(entry.checksum));
|
}
|
||||||
|
|
||||||
|
std::string full_path = entry.path().string();
|
||||||
|
std::string relative_path = entry.path().lexically_relative(dir_path).string();
|
||||||
|
|
||||||
|
// Convert backslashes to forward slashes (Windows compatibility)
|
||||||
|
std::ranges::replace(relative_path, '\\', '/');
|
||||||
|
|
||||||
|
// Skip development files
|
||||||
|
if (relative_path.find(".world") != std::string::npos ||
|
||||||
|
relative_path.find(".tsx") != std::string::npos) {
|
||||||
|
std::cout << "Skipping development file: " << relative_path << '\n';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string pack_name = current_base + relative_path;
|
||||||
|
addFile(full_path, pack_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt data
|
// Save the pack to a file
|
||||||
std::vector<uint8_t> encrypted_data = data_;
|
auto Pack::savePack(const std::string& pack_file) -> bool {
|
||||||
encryptData(encrypted_data, DEFAULT_ENCRYPT_KEY);
|
std::ofstream file(pack_file, std::ios::binary);
|
||||||
|
if (!file) {
|
||||||
|
std::cerr << "ResourcePack: Failed to create pack file: " << pack_file << '\n';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Write encrypted data size and data
|
// Write header
|
||||||
uint64_t data_size = encrypted_data.size();
|
file.write(MAGIC_HEADER.data(), MAGIC_HEADER.size());
|
||||||
file.write(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
|
file.write(reinterpret_cast<const char*>(&VERSION), sizeof(VERSION));
|
||||||
file.write(reinterpret_cast<const char*>(encrypted_data.data()), data_size);
|
|
||||||
|
|
||||||
std::cout << "\nPack saved successfully: " << pack_file << '\n';
|
// Write resource count
|
||||||
std::cout << "Resources: " << resource_count << '\n';
|
auto resource_count = static_cast<uint32_t>(resources_.size());
|
||||||
std::cout << "Total size: " << data_size << " bytes\n";
|
file.write(reinterpret_cast<const char*>(&resource_count), sizeof(resource_count));
|
||||||
|
|
||||||
return true;
|
// Write resource entries
|
||||||
}
|
for (const auto& [name, entry] : resources_) {
|
||||||
|
// Write filename length and name
|
||||||
|
auto name_len = static_cast<uint32_t>(entry.filename.length());
|
||||||
|
file.write(reinterpret_cast<const char*>(&name_len), sizeof(name_len));
|
||||||
|
file.write(entry.filename.c_str(), name_len);
|
||||||
|
|
||||||
// Load a pack from a file
|
// Write offset, size, checksum
|
||||||
auto Pack::loadPack(const std::string& pack_file) -> bool {
|
file.write(reinterpret_cast<const char*>(&entry.offset), sizeof(entry.offset));
|
||||||
std::ifstream file(pack_file, std::ios::binary);
|
file.write(reinterpret_cast<const char*>(&entry.size), sizeof(entry.size));
|
||||||
if (!file) {
|
file.write(reinterpret_cast<const char*>(&entry.checksum), sizeof(entry.checksum));
|
||||||
std::cerr << "ResourcePack: Failed to open pack file: " << pack_file << '\n';
|
}
|
||||||
return false;
|
|
||||||
|
// Encrypt data
|
||||||
|
std::vector<uint8_t> encrypted_data = data_;
|
||||||
|
encryptData(encrypted_data, DEFAULT_ENCRYPT_KEY);
|
||||||
|
|
||||||
|
// Write encrypted data size and data
|
||||||
|
uint64_t data_size = encrypted_data.size();
|
||||||
|
file.write(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
|
||||||
|
file.write(reinterpret_cast<const char*>(encrypted_data.data()), data_size);
|
||||||
|
|
||||||
|
std::cout << "\nPack saved successfully: " << pack_file << '\n';
|
||||||
|
std::cout << "Resources: " << resource_count << '\n';
|
||||||
|
std::cout << "Total size: " << data_size << " bytes\n";
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and verify header
|
// Load a pack from a file
|
||||||
std::array<char, 4> header{};
|
auto Pack::loadPack(const std::string& pack_file) -> bool {
|
||||||
file.read(header.data(), header.size());
|
std::ifstream file(pack_file, std::ios::binary);
|
||||||
if (header != MAGIC_HEADER) {
|
if (!file) {
|
||||||
std::cerr << "ResourcePack: Invalid pack header\n";
|
std::cerr << "ResourcePack: Failed to open pack file: " << pack_file << '\n';
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and verify header
|
||||||
|
std::array<char, 4> header{};
|
||||||
|
file.read(header.data(), header.size());
|
||||||
|
if (header != MAGIC_HEADER) {
|
||||||
|
std::cerr << "ResourcePack: Invalid pack header\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and verify version
|
||||||
|
uint32_t version = 0;
|
||||||
|
file.read(reinterpret_cast<char*>(&version), sizeof(version));
|
||||||
|
if (version != VERSION) {
|
||||||
|
std::cerr << "ResourcePack: Unsupported pack version: " << version << '\n';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read resource count
|
||||||
|
uint32_t resource_count = 0;
|
||||||
|
file.read(reinterpret_cast<char*>(&resource_count), sizeof(resource_count));
|
||||||
|
|
||||||
|
// Read resource entries
|
||||||
|
resources_.clear();
|
||||||
|
for (uint32_t i = 0; i < resource_count; ++i) {
|
||||||
|
// Read filename
|
||||||
|
uint32_t name_len = 0;
|
||||||
|
file.read(reinterpret_cast<char*>(&name_len), sizeof(name_len));
|
||||||
|
|
||||||
|
std::string filename(name_len, '\0');
|
||||||
|
file.read(filename.data(), name_len);
|
||||||
|
|
||||||
|
// Read entry data
|
||||||
|
ResourceEntry entry{};
|
||||||
|
entry.filename = filename;
|
||||||
|
file.read(reinterpret_cast<char*>(&entry.offset), sizeof(entry.offset));
|
||||||
|
file.read(reinterpret_cast<char*>(&entry.size), sizeof(entry.size));
|
||||||
|
file.read(reinterpret_cast<char*>(&entry.checksum), sizeof(entry.checksum));
|
||||||
|
|
||||||
|
resources_[filename] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read encrypted data
|
||||||
|
uint64_t data_size = 0;
|
||||||
|
file.read(reinterpret_cast<char*>(&data_size), sizeof(data_size));
|
||||||
|
|
||||||
|
data_.resize(data_size);
|
||||||
|
file.read(reinterpret_cast<char*>(data_.data()), data_size);
|
||||||
|
|
||||||
|
// Decrypt data
|
||||||
|
decryptData(data_, DEFAULT_ENCRYPT_KEY);
|
||||||
|
|
||||||
|
loaded_ = true;
|
||||||
|
|
||||||
|
std::cout << "ResourcePack loaded: " << pack_file << '\n';
|
||||||
|
std::cout << "Resources: " << resource_count << '\n';
|
||||||
|
std::cout << "Data size: " << data_size << " bytes\n";
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and verify version
|
// Get a resource by name
|
||||||
uint32_t version = 0;
|
auto Pack::getResource(const std::string& filename) -> std::vector<uint8_t> {
|
||||||
file.read(reinterpret_cast<char*>(&version), sizeof(version));
|
auto it = resources_.find(filename);
|
||||||
if (version != VERSION) {
|
if (it == resources_.end()) {
|
||||||
std::cerr << "ResourcePack: Unsupported pack version: " << version << '\n';
|
return {};
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
const ResourceEntry& entry = it->second;
|
||||||
|
|
||||||
|
// Extract data slice
|
||||||
|
if (entry.offset + entry.size > data_.size()) {
|
||||||
|
std::cerr << "ResourcePack: Invalid offset/size for: " << filename << '\n';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> result(data_.begin() + entry.offset,
|
||||||
|
data_.begin() + entry.offset + entry.size);
|
||||||
|
|
||||||
|
// Verify checksum
|
||||||
|
uint32_t checksum = calculateChecksum(result);
|
||||||
|
if (checksum != entry.checksum) {
|
||||||
|
std::cerr << "ResourcePack: Checksum mismatch for: " << filename << '\n';
|
||||||
|
std::cerr << " Expected: 0x" << std::hex << entry.checksum << '\n';
|
||||||
|
std::cerr << " Got: 0x" << std::hex << checksum << std::dec << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read resource count
|
// Check if a resource exists
|
||||||
uint32_t resource_count = 0;
|
auto Pack::hasResource(const std::string& filename) const -> bool {
|
||||||
file.read(reinterpret_cast<char*>(&resource_count), sizeof(resource_count));
|
return resources_.find(filename) != resources_.end();
|
||||||
|
|
||||||
// Read resource entries
|
|
||||||
resources_.clear();
|
|
||||||
for (uint32_t i = 0; i < resource_count; ++i) {
|
|
||||||
// Read filename
|
|
||||||
uint32_t name_len = 0;
|
|
||||||
file.read(reinterpret_cast<char*>(&name_len), sizeof(name_len));
|
|
||||||
|
|
||||||
std::string filename(name_len, '\0');
|
|
||||||
file.read(filename.data(), name_len);
|
|
||||||
|
|
||||||
// Read entry data
|
|
||||||
ResourceEntry entry{};
|
|
||||||
entry.filename = filename;
|
|
||||||
file.read(reinterpret_cast<char*>(&entry.offset), sizeof(entry.offset));
|
|
||||||
file.read(reinterpret_cast<char*>(&entry.size), sizeof(entry.size));
|
|
||||||
file.read(reinterpret_cast<char*>(&entry.checksum), sizeof(entry.checksum));
|
|
||||||
|
|
||||||
resources_[filename] = entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read encrypted data
|
// Get list of all resources
|
||||||
uint64_t data_size = 0;
|
auto Pack::getResourceList() const -> std::vector<std::string> {
|
||||||
file.read(reinterpret_cast<char*>(&data_size), sizeof(data_size));
|
std::vector<std::string> list;
|
||||||
|
list.reserve(resources_.size());
|
||||||
data_.resize(data_size);
|
for (const auto& [name, entry] : resources_) {
|
||||||
file.read(reinterpret_cast<char*>(data_.data()), data_size);
|
list.push_back(name);
|
||||||
|
}
|
||||||
// Decrypt data
|
std::ranges::sort(list);
|
||||||
decryptData(data_, DEFAULT_ENCRYPT_KEY);
|
return list;
|
||||||
|
|
||||||
loaded_ = true;
|
|
||||||
|
|
||||||
std::cout << "ResourcePack loaded: " << pack_file << '\n';
|
|
||||||
std::cout << "Resources: " << resource_count << '\n';
|
|
||||||
std::cout << "Data size: " << data_size << " bytes\n";
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a resource by name
|
|
||||||
auto Pack::getResource(const std::string& filename) -> std::vector<uint8_t> {
|
|
||||||
auto it = resources_.find(filename);
|
|
||||||
if (it == resources_.end()) {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResourceEntry& entry = it->second;
|
// Calculate overall pack checksum for validation
|
||||||
|
auto Pack::calculatePackChecksum() const -> uint32_t {
|
||||||
|
if (!loaded_ || data_.empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Extract data slice
|
// Combine checksums of all resources for a global checksum
|
||||||
if (entry.offset + entry.size > data_.size()) {
|
uint32_t global_checksum = 0x87654321;
|
||||||
std::cerr << "ResourcePack: Invalid offset/size for: " << filename << '\n';
|
|
||||||
return {};
|
// Sort resources by name for deterministic checksum
|
||||||
|
std::vector<std::string> sorted_names;
|
||||||
|
sorted_names.reserve(resources_.size());
|
||||||
|
for (const auto& [name, entry] : resources_) {
|
||||||
|
sorted_names.push_back(name);
|
||||||
|
}
|
||||||
|
std::ranges::sort(sorted_names);
|
||||||
|
|
||||||
|
// Combine individual checksums
|
||||||
|
for (const auto& name : sorted_names) {
|
||||||
|
const auto& entry = resources_.at(name);
|
||||||
|
global_checksum = ((global_checksum << 5) + global_checksum) + entry.checksum;
|
||||||
|
global_checksum = ((global_checksum << 5) + global_checksum) + entry.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return global_checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> result(data_.begin() + entry.offset,
|
|
||||||
data_.begin() + entry.offset + entry.size);
|
|
||||||
|
|
||||||
// Verify checksum
|
|
||||||
uint32_t checksum = calculateChecksum(result);
|
|
||||||
if (checksum != entry.checksum) {
|
|
||||||
std::cerr << "ResourcePack: Checksum mismatch for: " << filename << '\n';
|
|
||||||
std::cerr << " Expected: 0x" << std::hex << entry.checksum << '\n';
|
|
||||||
std::cerr << " Got: 0x" << std::hex << checksum << std::dec << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a resource exists
|
|
||||||
auto Pack::hasResource(const std::string& filename) const -> bool {
|
|
||||||
return resources_.find(filename) != resources_.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get list of all resources
|
|
||||||
auto Pack::getResourceList() const -> std::vector<std::string> {
|
|
||||||
std::vector<std::string> list;
|
|
||||||
list.reserve(resources_.size());
|
|
||||||
for (const auto& [name, entry] : resources_) {
|
|
||||||
list.push_back(name);
|
|
||||||
}
|
|
||||||
std::ranges::sort(list);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate overall pack checksum for validation
|
|
||||||
auto Pack::calculatePackChecksum() const -> uint32_t {
|
|
||||||
if (!loaded_ || data_.empty()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine checksums of all resources for a global checksum
|
|
||||||
uint32_t global_checksum = 0x87654321;
|
|
||||||
|
|
||||||
// Sort resources by name for deterministic checksum
|
|
||||||
std::vector<std::string> sorted_names;
|
|
||||||
sorted_names.reserve(resources_.size());
|
|
||||||
for (const auto& [name, entry] : resources_) {
|
|
||||||
sorted_names.push_back(name);
|
|
||||||
}
|
|
||||||
std::ranges::sort(sorted_names);
|
|
||||||
|
|
||||||
// Combine individual checksums
|
|
||||||
for (const auto& name : sorted_names) {
|
|
||||||
const auto& entry = resources_.at(name);
|
|
||||||
global_checksum = ((global_checksum << 5) + global_checksum) + entry.checksum;
|
|
||||||
global_checksum = ((global_checksum << 5) + global_checksum) + entry.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return global_checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -11,20 +11,20 @@
|
|||||||
|
|
||||||
namespace Resource {
|
namespace Resource {
|
||||||
|
|
||||||
// Entry metadata for each resource in the pack
|
// Entry metadata for each resource in the pack
|
||||||
struct ResourceEntry {
|
struct ResourceEntry {
|
||||||
std::string filename; // Relative path within pack
|
std::string filename; // Relative path within pack
|
||||||
uint64_t offset{0}; // Byte offset in data block
|
uint64_t offset{0}; // Byte offset in data block
|
||||||
uint64_t size{0}; // Size in bytes
|
uint64_t size{0}; // Size in bytes
|
||||||
uint32_t checksum{0}; // CRC32 checksum for verification
|
uint32_t checksum{0}; // CRC32 checksum for verification
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resource pack file format
|
// Resource pack file format
|
||||||
// Header: "JDDI" (4 bytes) + Version (4 bytes)
|
// Header: "JDDI" (4 bytes) + Version (4 bytes)
|
||||||
// Metadata: Count + array of ResourceEntry
|
// Metadata: Count + array of ResourceEntry
|
||||||
// Data: Encrypted data block
|
// Data: Encrypted data block
|
||||||
class Pack {
|
class Pack {
|
||||||
public:
|
public:
|
||||||
Pack() = default;
|
Pack() = default;
|
||||||
~Pack() = default;
|
~Pack() = default;
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ class Pack {
|
|||||||
auto getDataSize() const -> size_t { return data_.size(); }
|
auto getDataSize() const -> size_t { return data_.size(); }
|
||||||
auto calculatePackChecksum() const -> uint32_t; // Validation
|
auto calculatePackChecksum() const -> uint32_t; // Validation
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr std::array<char, 4> MAGIC_HEADER = {'J', 'D', 'D', 'I'}; // Pack format constants
|
static constexpr std::array<char, 4> MAGIC_HEADER = {'J', 'D', 'D', 'I'}; // Pack format constants
|
||||||
static constexpr uint32_t VERSION = 1;
|
static constexpr uint32_t VERSION = 1;
|
||||||
static constexpr const char* DEFAULT_ENCRYPT_KEY = "JDDI_RESOURCES_2024";
|
static constexpr const char* DEFAULT_ENCRYPT_KEY = "JDDI_RESOURCES_2024";
|
||||||
@@ -63,6 +63,6 @@ class Pack {
|
|||||||
std::unordered_map<std::string, ResourceEntry> resources_; // Member variables
|
std::unordered_map<std::string, ResourceEntry> resources_; // Member variables
|
||||||
std::vector<uint8_t> data_; // Encrypted data block
|
std::vector<uint8_t> data_; // Encrypted data block
|
||||||
bool loaded_{false};
|
bool loaded_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Resource
|
} // namespace Resource
|
||||||
|
|||||||
@@ -15,48 +15,48 @@ struct JA_Sound_t;
|
|||||||
|
|
||||||
// Estructura para almacenar ficheros de sonido y su nombre
|
// Estructura para almacenar ficheros de sonido y su nombre
|
||||||
struct SoundResource {
|
struct SoundResource {
|
||||||
std::string name; // Nombre del sonido
|
std::string name; // Nombre del sonido
|
||||||
JA_Sound_t* sound{nullptr}; // Objeto con el sonido
|
JA_Sound_t* sound{nullptr}; // Objeto con el sonido
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar ficheros musicales y su nombre
|
// Estructura para almacenar ficheros musicales y su nombre
|
||||||
struct MusicResource {
|
struct MusicResource {
|
||||||
std::string name; // Nombre de la musica
|
std::string name; // Nombre de la musica
|
||||||
JA_Music_t* music{nullptr}; // Objeto con la música
|
JA_Music_t* music{nullptr}; // Objeto con la música
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar objetos Surface y su nombre
|
// Estructura para almacenar objetos Surface y su nombre
|
||||||
struct SurfaceResource {
|
struct SurfaceResource {
|
||||||
std::string name; // Nombre de la surface
|
std::string name; // Nombre de la surface
|
||||||
std::shared_ptr<Surface> surface; // Objeto con la surface
|
std::shared_ptr<Surface> surface; // Objeto con la surface
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar objetos Palette y su nombre
|
// Estructura para almacenar objetos Palette y su nombre
|
||||||
struct ResourcePalette {
|
struct ResourcePalette {
|
||||||
std::string name; // Nombre de la surface
|
std::string name; // Nombre de la surface
|
||||||
Palette palette{}; // Paleta
|
Palette palette{}; // Paleta
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar ficheros TextFile y su nombre
|
// Estructura para almacenar ficheros TextFile y su nombre
|
||||||
struct TextFileResource {
|
struct TextFileResource {
|
||||||
std::string name; // Nombre del fichero
|
std::string name; // Nombre del fichero
|
||||||
std::shared_ptr<Text::File> text_file; // Objeto con los descriptores de la fuente de texto
|
std::shared_ptr<Text::File> text_file; // Objeto con los descriptores de la fuente de texto
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar objetos Text y su nombre
|
// Estructura para almacenar objetos Text y su nombre
|
||||||
struct TextResource {
|
struct TextResource {
|
||||||
std::string name; // Nombre del objeto
|
std::string name; // Nombre del objeto
|
||||||
std::shared_ptr<Text> text; // Objeto
|
std::shared_ptr<Text> text; // Objeto
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar ficheros animaciones y su nombre
|
// Estructura para almacenar ficheros animaciones y su nombre
|
||||||
struct AnimationResource {
|
struct AnimationResource {
|
||||||
std::string name; // Nombre del fichero
|
std::string name; // Nombre del fichero
|
||||||
std::vector<uint8_t> yaml_data; // Bytes del archivo YAML sin parsear
|
std::vector<uint8_t> yaml_data; // Bytes del archivo YAML sin parsear
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar habitaciones y su nombre
|
// Estructura para almacenar habitaciones y su nombre
|
||||||
struct RoomResource {
|
struct RoomResource {
|
||||||
std::string name; // Nombre de la habitación
|
std::string name; // Nombre de la habitación
|
||||||
std::shared_ptr<Room::Data> room; // Habitación
|
std::shared_ptr<Room::Data> room; // Habitación
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,36 +9,36 @@
|
|||||||
|
|
||||||
// Clase Debug
|
// Clase Debug
|
||||||
class Debug {
|
class Debug {
|
||||||
public:
|
public:
|
||||||
static void init(); // [SINGLETON] Crearemos el objeto con esta función estática
|
static void init(); // [SINGLETON] Crearemos el objeto con esta función estática
|
||||||
static void destroy(); // [SINGLETON] Destruiremos el objeto con esta función estática
|
static void destroy(); // [SINGLETON] Destruiremos el objeto con esta función estática
|
||||||
static auto get() -> Debug*; // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
static auto get() -> Debug*; // [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||||
|
|
||||||
void render(); // Dibuja en pantalla
|
void render(); // Dibuja en pantalla
|
||||||
|
|
||||||
void setPos(SDL_FPoint p); // Establece la posición donde se colocará la información de debug
|
void setPos(SDL_FPoint p); // Establece la posición donde se colocará la información de debug
|
||||||
|
|
||||||
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; } // Obtiene si el debug está activo
|
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; } // Obtiene si el debug está activo
|
||||||
|
|
||||||
void add(const std::string& text) { slot_.push_back(text); } // Añade texto al slot de debug
|
void add(const std::string& text) { slot_.push_back(text); } // Añade texto al slot de debug
|
||||||
void clear() { slot_.clear(); } // Limpia el slot de debug
|
void clear() { slot_.clear(); } // Limpia el slot de debug
|
||||||
void addToLog(const std::string& text) { log_.push_back(text); } // Añade texto al log
|
void addToLog(const std::string& text) { log_.push_back(text); } // Añade texto al log
|
||||||
void clearLog() { log_.clear(); } // Limpia el log
|
void clearLog() { log_.clear(); } // Limpia el log
|
||||||
void setEnabled(bool value) { enabled_ = value; } // Establece si el debug está activo
|
void setEnabled(bool value) { enabled_ = value; } // Establece si el debug está activo
|
||||||
void toggleEnabled() { enabled_ = !enabled_; } // Alterna el estado del debug
|
void toggleEnabled() { enabled_ = !enabled_; } // Alterna el estado del debug
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Debug* debug; // [SINGLETON] Objeto privado
|
static Debug* debug; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
Debug() = default; // Constructor
|
Debug() = default; // Constructor
|
||||||
~Debug() = default; // Destructor
|
~Debug() = default; // Destructor
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
std::vector<std::string> slot_; // Vector con los textos a escribir
|
std::vector<std::string> slot_; // Vector con los textos a escribir
|
||||||
std::vector<std::string> log_; // Vector con los textos a escribir
|
std::vector<std::string> log_; // Vector con los textos a escribir
|
||||||
int x_ = 0; // Posicion donde escribir el texto de debug
|
int x_ = 0; // Posicion donde escribir el texto de debug
|
||||||
int y_ = 0; // Posición donde escribir el texto de debug
|
int y_ = 0; // Posición donde escribir el texto de debug
|
||||||
bool enabled_ = false; // Indica si esta activo el modo debug
|
bool enabled_ = false; // Indica si esta activo el modo debug
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
@@ -6,27 +6,27 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class Director {
|
class Director {
|
||||||
public:
|
public:
|
||||||
explicit Director(std::vector<std::string> const& args); // Constructor
|
explicit Director(std::vector<std::string> const& args); // Constructor
|
||||||
~Director(); // Destructor
|
~Director(); // Destructor
|
||||||
static auto run() -> int; // Bucle principal
|
static auto run() -> int; // Bucle principal
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Variables ---
|
// --- Variables ---
|
||||||
std::string executable_path_; // Path del ejecutable
|
std::string executable_path_; // Path del ejecutable
|
||||||
std::string system_folder_; // Carpeta del sistema donde guardar datos
|
std::string system_folder_; // Carpeta del sistema donde guardar datos
|
||||||
static auto checkProgramArguments(std::vector<std::string> const& args) -> std::string; // Comprueba los parametros del programa
|
static auto checkProgramArguments(std::vector<std::string> const& args) -> std::string; // Comprueba los parametros del programa
|
||||||
|
|
||||||
// --- Funciones ---
|
// --- Funciones ---
|
||||||
void createSystemFolder(const std::string& folder); // Crea la carpeta del sistema donde guardar datos
|
void createSystemFolder(const std::string& folder); // Crea la carpeta del sistema donde guardar datos
|
||||||
void setFileList(); // Carga la configuración de assets desde assets.yaml
|
void setFileList(); // Carga la configuración de assets desde assets.yaml
|
||||||
static void runLogo(); // Ejecuta la seccion de juego con el logo
|
static void runLogo(); // Ejecuta la seccion de juego con el logo
|
||||||
static void runLoadingScreen(); // Ejecuta la seccion de juego de la pantalla de carga
|
static void runLoadingScreen(); // Ejecuta la seccion de juego de la pantalla de carga
|
||||||
static void runTitle(); // Ejecuta la seccion de juego con el titulo y los menus
|
static void runTitle(); // Ejecuta la seccion de juego con el titulo y los menus
|
||||||
static void runCredits(); // Ejecuta la seccion de los creditos del juego
|
static void runCredits(); // Ejecuta la seccion de los creditos del juego
|
||||||
static void runDemo(); // Ejecuta la seccion de la demo, donde se ven pantallas del juego
|
static void runDemo(); // Ejecuta la seccion de la demo, donde se ven pantallas del juego
|
||||||
static void runEnding(); // Ejecuta la seccion del final del juego
|
static void runEnding(); // Ejecuta la seccion del final del juego
|
||||||
static void runEnding2(); // Ejecuta la seccion del final del juego
|
static void runEnding2(); // Ejecuta la seccion del final del juego
|
||||||
static void runGameOver(); // Ejecuta la seccion del final de la partida
|
static void runGameOver(); // Ejecuta la seccion del final de la partida
|
||||||
static void runGame(); // Ejecuta la seccion de juego donde se juega
|
static void runGame(); // Ejecuta la seccion de juego donde se juega
|
||||||
};
|
};
|
||||||
@@ -5,18 +5,18 @@
|
|||||||
#include "game/scene_manager.hpp" // Para SceneManager
|
#include "game/scene_manager.hpp" // Para SceneManager
|
||||||
|
|
||||||
namespace GlobalEvents {
|
namespace GlobalEvents {
|
||||||
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||||
void handle(const SDL_Event& event) {
|
void handle(const SDL_Event& event) {
|
||||||
// Evento de salida de la aplicación
|
// Evento de salida de la aplicación
|
||||||
if (event.type == SDL_EVENT_QUIT) {
|
if (event.type == SDL_EVENT_QUIT) {
|
||||||
SceneManager::current = SceneManager::Scene::QUIT;
|
SceneManager::current = SceneManager::Scene::QUIT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.type == SDL_EVENT_RENDER_DEVICE_RESET || event.type == SDL_EVENT_RENDER_TARGETS_RESET) {
|
if (event.type == SDL_EVENT_RENDER_DEVICE_RESET || event.type == SDL_EVENT_RENDER_TARGETS_RESET) {
|
||||||
// reLoadTextures();
|
// reLoadTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mouse::handleEvent(event);
|
Mouse::handleEvent(event);
|
||||||
}
|
}
|
||||||
} // namespace GlobalEvents
|
} // namespace GlobalEvents
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
namespace GlobalEvents {
|
namespace GlobalEvents {
|
||||||
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||||
void handle(const SDL_Event& event);
|
void handle(const SDL_Event& event);
|
||||||
} // namespace GlobalEvents
|
} // namespace GlobalEvents
|
||||||
@@ -8,116 +8,95 @@
|
|||||||
|
|
||||||
// Forward declarations from Options namespace
|
// Forward declarations from Options namespace
|
||||||
namespace Options {
|
namespace Options {
|
||||||
// enum class ControlScheme;
|
// enum class ControlScheme;
|
||||||
enum class NotificationPosition;
|
enum class NotificationPosition;
|
||||||
} // namespace Options
|
} // namespace Options
|
||||||
|
|
||||||
namespace Defaults {
|
namespace Defaults::Canvas {
|
||||||
|
constexpr int WIDTH = GameCanvas::WIDTH; // Ancho del canvas del juego (256)
|
||||||
|
constexpr int HEIGHT = GameCanvas::HEIGHT; // Alto del canvas del juego (192)
|
||||||
|
} // namespace Defaults::Canvas
|
||||||
|
|
||||||
// --- CANVAS ---
|
namespace Defaults::Window {
|
||||||
// Dimensiones del canvas del juego (usa GameCanvas como fuente única)
|
constexpr int ZOOM = 2; // Zoom de la ventana por defecto
|
||||||
namespace Canvas {
|
} // namespace Defaults::Window
|
||||||
constexpr int WIDTH = GameCanvas::WIDTH; // Ancho del canvas del juego (256)
|
|
||||||
constexpr int HEIGHT = GameCanvas::HEIGHT; // Alto del canvas del juego (192)
|
|
||||||
} // namespace Canvas
|
|
||||||
|
|
||||||
// --- WINDOW ---
|
namespace Defaults::Video {
|
||||||
namespace Window {
|
constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana)
|
||||||
constexpr int ZOOM = 2; // Zoom de la ventana por defecto
|
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
|
||||||
} // namespace Window
|
constexpr bool VERTICAL_SYNC = true; // Vsync activado por defecto
|
||||||
|
constexpr bool POSTFX = false; // PostFX desactivado por defecto
|
||||||
|
constexpr bool INTEGER_SCALE = true; // Escalado entero activado por defecto
|
||||||
|
constexpr bool KEEP_ASPECT = true; // Mantener aspecto activado por defecto
|
||||||
|
constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto
|
||||||
|
} // namespace Defaults::Video
|
||||||
|
|
||||||
// --- VIDEO ---
|
namespace Defaults::Border {
|
||||||
namespace Video {
|
constexpr bool ENABLED = true; // Borde activado por defecto
|
||||||
constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana)
|
constexpr int WIDTH = 32; // Ancho del borde por defecto
|
||||||
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
|
constexpr int HEIGHT = 24; // Alto del borde por defectoF
|
||||||
constexpr bool VERTICAL_SYNC = true; // Vsync activado por defecto
|
} // namespace Defaults::Border
|
||||||
constexpr bool POSTFX = false; // PostFX desactivado por defecto
|
|
||||||
constexpr bool INTEGER_SCALE = true; // Escalado entero activado por defecto
|
|
||||||
constexpr bool KEEP_ASPECT = true; // Mantener aspecto activado por defecto
|
|
||||||
constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto
|
|
||||||
} // namespace Video
|
|
||||||
|
|
||||||
// --- BORDER ---
|
namespace Defaults::Audio {
|
||||||
namespace Border {
|
constexpr float VOLUME = 1.0F; // Volumen por defecto
|
||||||
constexpr bool ENABLED = true; // Borde activado por defecto
|
constexpr bool ENABLED = true; // Audio por defecto
|
||||||
constexpr int WIDTH = 32; // Ancho del borde por defecto
|
} // namespace Defaults::Audio
|
||||||
constexpr int HEIGHT = 24; // Alto del borde por defecto
|
|
||||||
} // namespace Border
|
|
||||||
|
|
||||||
// --- AUDIO ---
|
namespace Defaults::Music {
|
||||||
namespace Audio {
|
constexpr float VOLUME = 0.8F; // Volumen por defecto de la musica
|
||||||
constexpr float VOLUME = 1.0F; // Volumen por defecto
|
constexpr bool ENABLED = true; // Musica habilitada por defecto
|
||||||
constexpr bool ENABLED = true; // Audio por defecto
|
} // namespace Defaults::Music
|
||||||
} // namespace Audio
|
|
||||||
|
|
||||||
// --- MUSIC ---
|
namespace Defaults::Sound {
|
||||||
namespace Music {
|
constexpr float VOLUME = 1.0F; // Volumen por defecto de los efectos de sonido
|
||||||
constexpr float VOLUME = 0.8F; // Volumen por defecto de la musica
|
constexpr bool ENABLED = true; // Sonido habilitado por defecto
|
||||||
constexpr bool ENABLED = true; // Musica habilitada por defecto
|
} // namespace Defaults::Sound
|
||||||
} // namespace Music
|
|
||||||
|
|
||||||
// --- SOUND ---
|
namespace Defaults::Cheat {
|
||||||
namespace Sound {
|
constexpr bool INFINITE_LIVES = false; // Vidas infinitas desactivadas por defecto
|
||||||
constexpr float VOLUME = 1.0F; // Volumen por defecto de los efectos de sonido
|
constexpr bool INVINCIBLE = false; // Invencibilidad desactivada por defecto
|
||||||
constexpr bool ENABLED = true; // Sonido habilitado por defecto
|
constexpr bool JAIL_IS_OPEN = false; // Jail abierta desactivada por defecto
|
||||||
} // namespace Sound
|
constexpr bool ALTERNATE_SKIN = false; // Skin alternativa desactivada por defecto
|
||||||
|
} // namespace Defaults::Cheat
|
||||||
|
|
||||||
// --- CHEATS ---
|
namespace Defaults::Stats {
|
||||||
namespace Cheat {
|
constexpr int ROOMS = 0; // Habitaciones visitadas por defecto
|
||||||
constexpr bool INFINITE_LIVES = false; // Vidas infinitas desactivadas por defecto
|
constexpr int ITEMS = 0; // Items obtenidos por defecto
|
||||||
constexpr bool INVINCIBLE = false; // Invencibilidad desactivada por defecto
|
constexpr const char* WORST_NIGHTMARE = ""; // Habitación con más muertes por defecto
|
||||||
constexpr bool JAIL_IS_OPEN = false; // Jail abierta desactivada por defecto
|
} // namespace Defaults::Stats
|
||||||
constexpr bool ALTERNATE_SKIN = false; // Skin alternativa desactivada por defecto
|
|
||||||
} // namespace Cheat
|
|
||||||
|
|
||||||
// --- STATS ---
|
namespace Defaults::Controls {
|
||||||
namespace Stats {
|
constexpr SDL_Scancode KEY_LEFT = SDL_SCANCODE_LEFT; // Tecla izquierda por defecto
|
||||||
constexpr int ROOMS = 0; // Habitaciones visitadas por defecto
|
constexpr SDL_Scancode KEY_RIGHT = SDL_SCANCODE_RIGHT; // Tecla derecha por defecto
|
||||||
constexpr int ITEMS = 0; // Items obtenidos por defecto
|
constexpr SDL_Scancode KEY_JUMP = SDL_SCANCODE_UP; // Tecla salto por defecto
|
||||||
constexpr const char* WORST_NIGHTMARE = ""; // Habitación con más muertes por defecto
|
|
||||||
} // namespace Stats
|
|
||||||
|
|
||||||
// --- CONTROLS ---
|
constexpr int GAMEPAD_BUTTON_LEFT = SDL_GAMEPAD_BUTTON_DPAD_LEFT; // Botón izquierda por defecto
|
||||||
namespace Controls {
|
constexpr int GAMEPAD_BUTTON_RIGHT = SDL_GAMEPAD_BUTTON_DPAD_RIGHT; // Botón derecha por defecto
|
||||||
constexpr SDL_Scancode KEY_LEFT = SDL_SCANCODE_LEFT; // Tecla izquierda por defecto
|
constexpr int GAMEPAD_BUTTON_JUMP = SDL_GAMEPAD_BUTTON_WEST; // Botón salto por defecto
|
||||||
constexpr SDL_Scancode KEY_RIGHT = SDL_SCANCODE_RIGHT; // Tecla derecha por defecto
|
} // namespace Defaults::Controls
|
||||||
constexpr SDL_Scancode KEY_JUMP = SDL_SCANCODE_UP; // Tecla salto por defecto
|
|
||||||
|
|
||||||
constexpr int GAMEPAD_BUTTON_LEFT = SDL_GAMEPAD_BUTTON_DPAD_LEFT; // Botón izquierda por defecto
|
namespace Defaults::Kiosk {
|
||||||
constexpr int GAMEPAD_BUTTON_RIGHT = SDL_GAMEPAD_BUTTON_DPAD_RIGHT; // Botón derecha por defecto
|
constexpr bool ENABLED = false; // Modo kiosko desactivado por defecto
|
||||||
constexpr int GAMEPAD_BUTTON_JUMP = SDL_GAMEPAD_BUTTON_WEST; // Botón salto por defecto
|
constexpr const char* TEXT = ""; // Texto del modo kiosko por defecto
|
||||||
} // namespace Controls
|
constexpr bool INFINITE_LIVES = false; // Vidas infinitas en modo kiosko desactivadas por defecto
|
||||||
|
} // namespace Defaults::Kiosk
|
||||||
|
|
||||||
// --- KIOSK ---
|
namespace Defaults::Game::Room {
|
||||||
namespace Kiosk {
|
|
||||||
constexpr bool ENABLED = false; // Modo kiosko desactivado por defecto
|
|
||||||
constexpr const char* TEXT = ""; // Texto del modo kiosko por defecto
|
|
||||||
constexpr bool INFINITE_LIVES = false; // Vidas infinitas en modo kiosko desactivadas por defecto
|
|
||||||
} // namespace Kiosk
|
|
||||||
|
|
||||||
// --- GAME (posición y habitación inicial) ---
|
|
||||||
namespace Game {
|
|
||||||
|
|
||||||
namespace Room {
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
constexpr const char* INITIAL = "51.yaml"; // Habitación de inicio en debug
|
constexpr const char* INITIAL = "51.yaml"; // Habitación de inicio en debug
|
||||||
#else
|
#else
|
||||||
constexpr const char* INITIAL = "03.yaml"; // Habitación de inicio en release
|
constexpr const char* INITIAL = "03.yaml"; // Habitación de inicio en release
|
||||||
#endif
|
#endif
|
||||||
} // namespace Room
|
} // namespace Defaults::Game::Room
|
||||||
|
|
||||||
namespace Player {
|
namespace Defaults::Game::Player {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
constexpr int SPAWN_X = 26 * Tile::SIZE; // Posición X inicial en debug
|
constexpr int SPAWN_X = 26 * Tile::SIZE; // Posición X inicial en debug
|
||||||
constexpr int SPAWN_Y = 10 * Tile::SIZE; // Posición Y inicial en debug
|
constexpr int SPAWN_Y = 10 * Tile::SIZE; // Posición Y inicial en debug
|
||||||
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en debug
|
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en debug
|
||||||
#else
|
#else
|
||||||
constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial en release
|
constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial en release
|
||||||
constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial en release
|
constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial en release
|
||||||
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en release
|
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en release
|
||||||
#endif
|
#endif
|
||||||
} // namespace Player
|
} // namespace Defaults::Game::Player
|
||||||
|
|
||||||
} // namespace Game
|
|
||||||
|
|
||||||
} // namespace Defaults
|
|
||||||
|
|||||||
@@ -7,45 +7,45 @@
|
|||||||
class SurfaceAnimatedSprite; // lines 7-7
|
class SurfaceAnimatedSprite; // lines 7-7
|
||||||
|
|
||||||
class Enemy {
|
class Enemy {
|
||||||
public:
|
public:
|
||||||
struct Data {
|
struct Data {
|
||||||
std::string animation_path; // Ruta al fichero con la animación
|
std::string animation_path; // Ruta al fichero con la animación
|
||||||
float x{0.0F}; // Posición inicial en el eje X
|
float x{0.0F}; // Posición inicial en el eje X
|
||||||
float y{0.0F}; // Posición inicial en el eje Y
|
float y{0.0F}; // Posición inicial en el eje Y
|
||||||
float vx{0.0F}; // Velocidad en el eje X
|
float vx{0.0F}; // Velocidad en el eje X
|
||||||
float vy{0.0F}; // Velocidad en el eje Y
|
float vy{0.0F}; // Velocidad en el eje Y
|
||||||
int x1{0}; // Límite izquierdo de la ruta en el eje X
|
int x1{0}; // Límite izquierdo de la ruta en el eje X
|
||||||
int x2{0}; // Límite derecho de la ruta en el eje X
|
int x2{0}; // Límite derecho de la ruta en el eje X
|
||||||
int y1{0}; // Límite superior de la ruta en el eje Y
|
int y1{0}; // Límite superior de la ruta en el eje Y
|
||||||
int y2{0}; // Límite inferior de la ruta en el eje Y
|
int y2{0}; // Límite inferior de la ruta en el eje Y
|
||||||
bool flip{false}; // Indica si el enemigo hace flip al terminar su ruta
|
bool flip{false}; // Indica si el enemigo hace flip al terminar su ruta
|
||||||
bool mirror{false}; // Indica si el enemigo está volteado verticalmente
|
bool mirror{false}; // Indica si el enemigo está volteado verticalmente
|
||||||
int frame{0}; // Frame inicial para la animación del enemigo
|
int frame{0}; // Frame inicial para la animación del enemigo
|
||||||
std::string color; // Color del enemigo
|
std::string color; // Color del enemigo
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Enemy(const Data& enemy); // Constructor
|
explicit Enemy(const Data& enemy); // Constructor
|
||||||
~Enemy() = default; // Destructor
|
~Enemy() = default; // Destructor
|
||||||
|
|
||||||
void render(); // Pinta el enemigo en pantalla
|
void render(); // Pinta el enemigo en pantalla
|
||||||
void update(float delta_time); // Actualiza las variables del objeto
|
void update(float delta_time); // Actualiza las variables del objeto
|
||||||
|
|
||||||
auto getRect() -> SDL_FRect; // Devuelve el rectangulo que contiene al enemigo
|
auto getRect() -> SDL_FRect; // Devuelve el rectangulo que contiene al enemigo
|
||||||
auto getCollider() -> SDL_FRect&; // Obtiene el rectangulo de colision del enemigo
|
auto getCollider() -> SDL_FRect&; // Obtiene el rectangulo de colision del enemigo
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkPath(); // Comprueba si ha llegado al limite del recorrido para darse media vuelta
|
void checkPath(); // Comprueba si ha llegado al limite del recorrido para darse media vuelta
|
||||||
|
|
||||||
std::shared_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del enemigo
|
std::shared_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del enemigo
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
Uint8 color_{0}; // Color del enemigo
|
Uint8 color_{0}; // Color del enemigo
|
||||||
std::string color_string_; // Color del enemigo en formato texto
|
std::string color_string_; // Color del enemigo en formato texto
|
||||||
int x1_{0}; // Limite izquierdo de la ruta en el eje X
|
int x1_{0}; // Limite izquierdo de la ruta en el eje X
|
||||||
int x2_{0}; // Limite derecho de la ruta en el eje X
|
int x2_{0}; // Limite derecho de la ruta en el eje X
|
||||||
int y1_{0}; // Limite superior de la ruta en el eje Y
|
int y1_{0}; // Limite superior de la ruta en el eje Y
|
||||||
int y2_{0}; // Limite inferior de la ruta en el eje Y
|
int y2_{0}; // Limite inferior de la ruta en el eje Y
|
||||||
SDL_FRect collider_{}; // Caja de colisión
|
SDL_FRect collider_{}; // Caja de colisión
|
||||||
bool should_flip_{false}; // Indica si el enemigo hace flip al terminar su ruta
|
bool should_flip_{false}; // Indica si el enemigo hace flip al terminar su ruta
|
||||||
bool should_mirror_{false}; // Indica si el enemigo se dibuja volteado verticalmente
|
bool should_mirror_{false}; // Indica si el enemigo se dibuja volteado verticalmente
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,37 +8,37 @@
|
|||||||
class SurfaceSprite;
|
class SurfaceSprite;
|
||||||
|
|
||||||
class Item {
|
class Item {
|
||||||
public:
|
public:
|
||||||
struct Data {
|
struct Data {
|
||||||
std::string tile_set_file; // Ruta al fichero con los gráficos del item
|
std::string tile_set_file; // Ruta al fichero con los gráficos del item
|
||||||
float x{0.0F}; // Posición del item en pantalla
|
float x{0.0F}; // Posición del item en pantalla
|
||||||
float y{0.0F}; // Posición del item en pantalla
|
float y{0.0F}; // Posición del item en pantalla
|
||||||
int tile{0}; // Número de tile dentro de la textura
|
int tile{0}; // Número de tile dentro de la textura
|
||||||
int counter{0}; // Contador inicial. Es el que lo hace cambiar de color
|
int counter{0}; // Contador inicial. Es el que lo hace cambiar de color
|
||||||
Uint8 color1{0}; // Uno de los dos colores que se utiliza para el item
|
Uint8 color1{0}; // Uno de los dos colores que se utiliza para el item
|
||||||
Uint8 color2{0}; // Uno de los dos colores que se utiliza para el item
|
Uint8 color2{0}; // Uno de los dos colores que se utiliza para el item
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Item(const Data& item); // Constructor
|
explicit Item(const Data& item); // Constructor
|
||||||
~Item() = default; // Destructor
|
~Item() = default; // Destructor
|
||||||
|
|
||||||
void render() const; // Pinta el objeto en pantalla
|
void render() const; // Pinta el objeto en pantalla
|
||||||
void update(float delta_time); // Actualiza las variables del objeto
|
void update(float delta_time); // Actualiza las variables del objeto
|
||||||
|
|
||||||
void setPaused(bool paused) { is_paused_ = paused; } // Pausa/despausa el item
|
void setPaused(bool paused) { is_paused_ = paused; } // Pausa/despausa el item
|
||||||
auto getCollider() -> SDL_FRect& { return collider_; } // Obtiene el rectangulo de colision del objeto
|
auto getCollider() -> SDL_FRect& { return collider_; } // Obtiene el rectangulo de colision del objeto
|
||||||
auto getPos() -> SDL_FPoint; // Obtiene su ubicación
|
auto getPos() -> SDL_FPoint; // Obtiene su ubicación
|
||||||
void setColors(Uint8 col1, Uint8 col2); // Asigna los colores del objeto
|
void setColors(Uint8 col1, Uint8 col2); // Asigna los colores del objeto
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr float ITEM_SIZE = 8.0F; // Tamaño del item en pixels
|
static constexpr float ITEM_SIZE = 8.0F; // Tamaño del item en pixels
|
||||||
static constexpr float COLOR_CHANGE_INTERVAL = 0.06F; // Intervalo de cambio de color en segundos (4 frames a 66.67fps)
|
static constexpr float COLOR_CHANGE_INTERVAL = 0.06F; // Intervalo de cambio de color en segundos (4 frames a 66.67fps)
|
||||||
|
|
||||||
std::shared_ptr<SurfaceSprite> sprite_; // SSprite del objeto
|
std::shared_ptr<SurfaceSprite> sprite_; // SSprite del objeto
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
std::vector<Uint8> color_; // Vector con los colores del objeto
|
std::vector<Uint8> color_; // Vector con los colores del objeto
|
||||||
float time_accumulator_{0.0F}; // Acumulador de tiempo para cambio de color
|
float time_accumulator_{0.0F}; // Acumulador de tiempo para cambio de color
|
||||||
SDL_FRect collider_{}; // Rectangulo de colisión
|
SDL_FRect collider_{}; // Rectangulo de colisión
|
||||||
bool is_paused_{false}; // Indica si el item está pausado
|
bool is_paused_{false}; // Indica si el item está pausado
|
||||||
};
|
};
|
||||||
@@ -16,206 +16,206 @@
|
|||||||
struct JA_Sound_t; // lines 13-13
|
struct JA_Sound_t; // lines 13-13
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
public:
|
public:
|
||||||
// --- Enums y Structs ---
|
// --- Enums y Structs ---
|
||||||
enum class State {
|
enum class State {
|
||||||
ON_GROUND, // En suelo plano o conveyor belt
|
ON_GROUND, // En suelo plano o conveyor belt
|
||||||
ON_SLOPE, // En rampa/pendiente
|
ON_SLOPE, // En rampa/pendiente
|
||||||
JUMPING,
|
JUMPING,
|
||||||
FALLING,
|
FALLING,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Direction {
|
enum class Direction {
|
||||||
LEFT,
|
LEFT,
|
||||||
RIGHT,
|
RIGHT,
|
||||||
UP,
|
UP,
|
||||||
DOWN,
|
DOWN,
|
||||||
NONE
|
NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de física (públicas para permitir cálculos en structs) ---
|
// --- Constantes de física (públicas para permitir cálculos en structs) ---
|
||||||
static constexpr float HORIZONTAL_VELOCITY = 40.0F; // Velocidad horizontal en pixels/segundo (0.6 * 66.67fps)
|
static constexpr float HORIZONTAL_VELOCITY = 40.0F; // Velocidad horizontal en pixels/segundo (0.6 * 66.67fps)
|
||||||
static constexpr float MAX_VY = 80.0F; // Velocidad vertical máxima en pixels/segundo (1.2 * 66.67fps)
|
static constexpr float MAX_VY = 80.0F; // Velocidad vertical máxima en pixels/segundo (1.2 * 66.67fps)
|
||||||
static constexpr float JUMP_VELOCITY = -80.0F; // Velocidad inicial del salto en pixels/segundo
|
static constexpr float JUMP_VELOCITY = -80.0F; // Velocidad inicial del salto en pixels/segundo
|
||||||
static constexpr float GRAVITY_FORCE = 155.6F; // Fuerza de gravedad en pixels/segundo² (0.035 * 66.67²)
|
static constexpr float GRAVITY_FORCE = 155.6F; // Fuerza de gravedad en pixels/segundo² (0.035 * 66.67²)
|
||||||
|
|
||||||
struct SpawnData {
|
struct SpawnData {
|
||||||
float x = 0;
|
float x = 0;
|
||||||
float y = 0;
|
float y = 0;
|
||||||
float vx = 0;
|
float vx = 0;
|
||||||
float vy = 0;
|
float vy = 0;
|
||||||
int last_grounded_position = 0;
|
int last_grounded_position = 0;
|
||||||
State state = State::ON_GROUND;
|
State state = State::ON_GROUND;
|
||||||
SDL_FlipMode flip = SDL_FLIP_NONE;
|
SDL_FlipMode flip = SDL_FLIP_NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
SpawnData spawn_data;
|
SpawnData spawn_data;
|
||||||
std::string animations_path;
|
std::string animations_path;
|
||||||
std::shared_ptr<Room> room = nullptr;
|
std::shared_ptr<Room> room = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JumpSoundController {
|
struct JumpSoundController {
|
||||||
// Duración del salto calculada automáticamente con física: t = 2 * v0 / g
|
// Duración del salto calculada automáticamente con física: t = 2 * v0 / g
|
||||||
static constexpr float JUMP_DURATION = (2.0F * MAX_VY) / GRAVITY_FORCE;
|
static constexpr float JUMP_DURATION = (2.0F * MAX_VY) / GRAVITY_FORCE;
|
||||||
static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1)
|
static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1)
|
||||||
static constexpr size_t LAST_SOUND = 17; // Último sonido a reproducir (índice 17)
|
static constexpr size_t LAST_SOUND = 17; // Último sonido a reproducir (índice 17)
|
||||||
static constexpr float SECONDS_PER_SOUND = JUMP_DURATION / (LAST_SOUND - FIRST_SOUND + 1);
|
static constexpr float SECONDS_PER_SOUND = JUMP_DURATION / (LAST_SOUND - FIRST_SOUND + 1);
|
||||||
|
|
||||||
size_t current_index = 0; // Índice del sonido actual
|
size_t current_index = 0; // Índice del sonido actual
|
||||||
float elapsed_time = 0.0F; // Tiempo transcurrido durante el salto
|
float elapsed_time = 0.0F; // Tiempo transcurrido durante el salto
|
||||||
bool active = false; // Indica si el controlador está activo
|
bool active = false; // Indica si el controlador está activo
|
||||||
|
|
||||||
void start(); // Inicia el controlador
|
void start(); // Inicia el controlador
|
||||||
void reset(); // Resetea el controlador
|
void reset(); // Resetea el controlador
|
||||||
auto shouldPlay(float delta_time, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
|
auto shouldPlay(float delta_time, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FallSoundController {
|
struct FallSoundController {
|
||||||
static constexpr float PIXELS_PER_SOUND = 5.0F; // Intervalo de píxeles por sonido (configurable)
|
static constexpr float PIXELS_PER_SOUND = 5.0F; // Intervalo de píxeles por sonido (configurable)
|
||||||
static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1)
|
static constexpr size_t FIRST_SOUND = 1; // Primer sonido a reproducir (índice 1)
|
||||||
static constexpr size_t LAST_SOUND = 13; // Último sonido a reproducir (índice 13)
|
static constexpr size_t LAST_SOUND = 13; // Último sonido a reproducir (índice 13)
|
||||||
|
|
||||||
size_t current_index = 0; // Índice del sonido actual
|
size_t current_index = 0; // Índice del sonido actual
|
||||||
float distance_traveled = 0.0F; // Distancia acumulada durante la caída
|
float distance_traveled = 0.0F; // Distancia acumulada durante la caída
|
||||||
float last_y = 0.0F; // Última posición Y registrada
|
float last_y = 0.0F; // Última posición Y registrada
|
||||||
bool active = false; // Indica si el controlador está activo
|
bool active = false; // Indica si el controlador está activo
|
||||||
|
|
||||||
void start(float start_y); // Inicia el controlador
|
void start(float start_y); // Inicia el controlador
|
||||||
void reset(); // Resetea el controlador
|
void reset(); // Resetea el controlador
|
||||||
auto shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
|
auto shouldPlay(float delta_time, float current_y, size_t& out_index) -> bool; // Comprueba si debe reproducir un sonido
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
explicit Player(const Data& player);
|
explicit Player(const Data& player);
|
||||||
~Player() = default;
|
~Player() = default;
|
||||||
|
|
||||||
// --- Funciones ---
|
// --- Funciones ---
|
||||||
void render(); // Pinta el enemigo en pantalla
|
void render(); // Pinta el enemigo en pantalla
|
||||||
void update(float delta_time); // Actualiza las variables del objeto
|
void update(float delta_time); // Actualiza las variables del objeto
|
||||||
[[nodiscard]] auto isOnBorder() const -> bool { return border_ != Room::Border::NONE; } // Indica si el jugador esta en uno de los cuatro bordes de la pantalla
|
[[nodiscard]] auto isOnBorder() const -> bool { return border_ != Room::Border::NONE; } // Indica si el jugador esta en uno de los cuatro bordes de la pantalla
|
||||||
[[nodiscard]] auto getBorder() const -> Room::Border { return border_; } // Indica en cual de los cuatro bordes se encuentra
|
[[nodiscard]] auto getBorder() const -> Room::Border { return border_; } // Indica en cual de los cuatro bordes se encuentra
|
||||||
void switchBorders(); // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
|
void switchBorders(); // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
|
||||||
auto getRect() -> SDL_FRect { return {x_, y_, WIDTH, HEIGHT}; } // Obtiene el rectangulo que delimita al jugador
|
auto getRect() -> SDL_FRect { return {x_, y_, WIDTH, HEIGHT}; } // Obtiene el rectangulo que delimita al jugador
|
||||||
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
|
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
|
||||||
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
|
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
|
||||||
void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats)
|
void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats)
|
||||||
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador
|
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador
|
||||||
//[[nodiscard]] auto isAlive() const -> bool { return is_alive_ || (Options::cheats.invincible == Options::Cheat::State::ENABLED); } // Comprueba si el jugador esta vivo
|
//[[nodiscard]] auto isAlive() const -> bool { return is_alive_ || (Options::cheats.invincible == Options::Cheat::State::ENABLED); } // Comprueba si el jugador esta vivo
|
||||||
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo
|
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo
|
||||||
void setPaused(bool value) { is_paused_ = value; } // Pone el jugador en modo pausa
|
void setPaused(bool value) { is_paused_ = value; } // Pone el jugador en modo pausa
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// --- Funciones de debug ---
|
// --- Funciones de debug ---
|
||||||
void setDebugPosition(float x, float y); // Establece la posición del jugador directamente (debug)
|
void setDebugPosition(float x, float y); // Establece la posición del jugador directamente (debug)
|
||||||
void finalizeDebugTeleport(); // Fija estado ON_GROUND, velocidades a 0, actualiza last_grounded_position_ (debug)
|
void finalizeDebugTeleport(); // Fija estado ON_GROUND, velocidades a 0, actualiza last_grounded_position_ (debug)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr int WIDTH = 8; // Ancho del jugador
|
static constexpr int WIDTH = 8; // Ancho del jugador
|
||||||
static constexpr int HEIGHT = 16; // ALto del jugador
|
static constexpr int HEIGHT = 16; // ALto del jugador
|
||||||
static constexpr int MAX_FALLING_HEIGHT = Tile::SIZE * 4; // Altura maxima permitida de caída en pixels
|
static constexpr int MAX_FALLING_HEIGHT = Tile::SIZE * 4; // Altura maxima permitida de caída en pixels
|
||||||
|
|
||||||
// --- Objetos y punteros ---
|
// --- Objetos y punteros ---
|
||||||
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
||||||
std::unique_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del jugador
|
std::unique_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del jugador
|
||||||
|
|
||||||
// --- Variables de posición y física ---
|
// --- Variables de posición y física ---
|
||||||
float x_ = 0.0F; // Posición del jugador en el eje X
|
float x_ = 0.0F; // Posición del jugador en el eje X
|
||||||
float y_ = 0.0F; // Posición del jugador en el eje Y
|
float y_ = 0.0F; // Posición del jugador en el eje Y
|
||||||
float y_prev_ = 0.0F; // Posición Y del frame anterior (para detectar hitos de distancia en sonidos)
|
float y_prev_ = 0.0F; // Posición Y del frame anterior (para detectar hitos de distancia en sonidos)
|
||||||
float vx_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje X
|
float vx_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje X
|
||||||
float vy_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje Y
|
float vy_ = 0.0F; // Velocidad/desplazamiento del jugador en el eje Y
|
||||||
|
|
||||||
Direction wanna_go_ = Direction::NONE;
|
Direction wanna_go_ = Direction::NONE;
|
||||||
bool wanna_jump_ = false;
|
bool wanna_jump_ = false;
|
||||||
|
|
||||||
// --- Variables de estado ---
|
// --- Variables de estado ---
|
||||||
State state_ = State::ON_GROUND; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
|
State state_ = State::ON_GROUND; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
|
||||||
State previous_state_ = State::ON_GROUND; // Estado previo en el que se encontraba el jugador
|
State previous_state_ = State::ON_GROUND; // Estado previo en el que se encontraba el jugador
|
||||||
|
|
||||||
// --- Variables de colisión ---
|
// --- Variables de colisión ---
|
||||||
SDL_FRect collider_box_{}; // Caja de colisión con los enemigos u objetos
|
SDL_FRect collider_box_{}; // Caja de colisión con los enemigos u objetos
|
||||||
std::array<SDL_FPoint, 8> collider_points_{}; // Puntos de colisión con el mapa
|
std::array<SDL_FPoint, 8> collider_points_{}; // Puntos de colisión con el mapa
|
||||||
SDL_FPoint under_left_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior izquierda del jugador
|
SDL_FPoint under_left_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior izquierda del jugador
|
||||||
SDL_FPoint under_right_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior derecha del jugador
|
SDL_FPoint under_right_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior derecha del jugador
|
||||||
const LineDiagonal* current_slope_{nullptr}; // Rampa actual sobe la que está el jugador
|
const LineDiagonal* current_slope_{nullptr}; // Rampa actual sobe la que está el jugador
|
||||||
|
|
||||||
// --- Variables de juego ---
|
// --- Variables de juego ---
|
||||||
bool is_alive_ = true; // Indica si el jugador esta vivo o no
|
bool is_alive_ = true; // Indica si el jugador esta vivo o no
|
||||||
bool is_paused_ = false; // Indica si el jugador esta en modo pausa
|
bool is_paused_ = false; // Indica si el jugador esta en modo pausa
|
||||||
bool auto_movement_ = false; // Indica si esta siendo arrastrado por una superficie automatica
|
bool auto_movement_ = false; // Indica si esta siendo arrastrado por una superficie automatica
|
||||||
Room::Border border_ = Room::Border::TOP; // Indica en cual de los cuatro bordes se encuentra
|
Room::Border border_ = Room::Border::TOP; // Indica en cual de los cuatro bordes se encuentra
|
||||||
int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto)
|
int last_grounded_position_ = 0; // Ultima posición en Y en la que se estaba en contacto con el suelo (hace doble función: tracking de caída + altura inicial del salto)
|
||||||
|
|
||||||
// --- Variables de renderizado y sonido ---
|
// --- Variables de renderizado y sonido ---
|
||||||
Uint8 color_ = 0; // Color del jugador
|
Uint8 color_ = 0; // Color del jugador
|
||||||
std::array<JA_Sound_t*, 24> jumping_sound_{}; // Array con todos los sonidos del salto
|
std::array<JA_Sound_t*, 24> jumping_sound_{}; // Array con todos los sonidos del salto
|
||||||
std::array<JA_Sound_t*, 14> falling_sound_{}; // Array con todos los sonidos de la caída
|
std::array<JA_Sound_t*, 14> falling_sound_{}; // Array con todos los sonidos de la caída
|
||||||
JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto
|
JumpSoundController jump_sound_ctrl_; // Controlador de sonidos de salto
|
||||||
FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída
|
FallSoundController fall_sound_ctrl_; // Controlador de sonidos de caída
|
||||||
int fall_start_position_ = 0; // Posición Y al iniciar la caída
|
int fall_start_position_ = 0; // Posición Y al iniciar la caída
|
||||||
|
|
||||||
void handleConveyorBelts();
|
void handleConveyorBelts();
|
||||||
void handleShouldFall();
|
void handleShouldFall();
|
||||||
void updateState(float delta_time);
|
void updateState(float delta_time);
|
||||||
|
|
||||||
// --- Métodos de actualización por estado ---
|
// --- Métodos de actualización por estado ---
|
||||||
void updateOnGround(float delta_time); // Actualización lógica estado ON_GROUND
|
void updateOnGround(float delta_time); // Actualización lógica estado ON_GROUND
|
||||||
void updateOnSlope(float delta_time); // Actualización lógica estado ON_SLOPE
|
void updateOnSlope(float delta_time); // Actualización lógica estado ON_SLOPE
|
||||||
void updateJumping(float delta_time); // Actualización lógica estado JUMPING
|
void updateJumping(float delta_time); // Actualización lógica estado JUMPING
|
||||||
void updateFalling(float delta_time); // Actualización lógica estado FALLING
|
void updateFalling(float delta_time); // Actualización lógica estado FALLING
|
||||||
|
|
||||||
// --- Métodos de movimiento por estado ---
|
// --- Métodos de movimiento por estado ---
|
||||||
void moveOnGround(float delta_time); // Movimiento físico estado ON_GROUND
|
void moveOnGround(float delta_time); // Movimiento físico estado ON_GROUND
|
||||||
void moveOnSlope(float delta_time); // Movimiento físico estado ON_SLOPE
|
void moveOnSlope(float delta_time); // Movimiento físico estado ON_SLOPE
|
||||||
void moveJumping(float delta_time); // Movimiento físico estado JUMPING
|
void moveJumping(float delta_time); // Movimiento físico estado JUMPING
|
||||||
void moveFalling(float delta_time); // Movimiento físico estado FALLING
|
void moveFalling(float delta_time); // Movimiento físico estado FALLING
|
||||||
|
|
||||||
// --- Funciones de inicialización ---
|
// --- Funciones de inicialización ---
|
||||||
void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador
|
void initSprite(const std::string& animations_path); // Inicializa el sprite del jugador
|
||||||
void initSounds(); // Inicializa los sonidos de salto y caida
|
void initSounds(); // Inicializa los sonidos de salto y caida
|
||||||
void applySpawnValues(const SpawnData& spawn); // Aplica los valores de spawn al jugador
|
void applySpawnValues(const SpawnData& spawn); // Aplica los valores de spawn al jugador
|
||||||
|
|
||||||
// --- Funciones de procesamiento de entrada ---
|
// --- Funciones de procesamiento de entrada ---
|
||||||
void handleInput(); // Comprueba las entradas y modifica variables
|
void handleInput(); // Comprueba las entradas y modifica variables
|
||||||
|
|
||||||
// --- Funciones de gestión de estado ---
|
// --- Funciones de gestión de estado ---
|
||||||
void transitionToState(State state); // Cambia el estado del jugador
|
void transitionToState(State state); // Cambia el estado del jugador
|
||||||
|
|
||||||
// --- Funciones de física ---
|
// --- Funciones de física ---
|
||||||
void applyGravity(float delta_time); // Aplica gravedad al jugador
|
void applyGravity(float delta_time); // Aplica gravedad al jugador
|
||||||
|
|
||||||
// --- Funciones de movimiento y colisión ---
|
// --- Funciones de movimiento y colisión ---
|
||||||
void move(float delta_time); // Orquesta el movimiento del jugador
|
void move(float delta_time); // Orquesta el movimiento del jugador
|
||||||
auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion
|
auto getProjection(Direction direction, float displacement) -> SDL_FRect; // Devuelve el rectangulo de proyeccion
|
||||||
void applyHorizontalMovement(float delta_time); // Aplica movimiento horizontal con colisión de muros
|
void applyHorizontalMovement(float delta_time); // Aplica movimiento horizontal con colisión de muros
|
||||||
auto handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool; // Detecta aterrizaje en superficies y rampas
|
auto handleLandingFromAir(float displacement, const SDL_FRect& projection) -> bool; // Detecta aterrizaje en superficies y rampas
|
||||||
void resetSoundControllersOnLanding(); // Resetea los controladores de sonido al aterrizar
|
void resetSoundControllersOnLanding(); // Resetea los controladores de sonido al aterrizar
|
||||||
|
|
||||||
// --- Funciones de detección de superficies ---
|
// --- Funciones de detección de superficies ---
|
||||||
auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies
|
auto isOnFloor() -> bool; // Comprueba si el jugador tiene suelo debajo de los pies
|
||||||
auto isOnTopSurface() -> bool; // Comprueba si el jugador está sobre una superficie
|
auto isOnTopSurface() -> bool; // Comprueba si el jugador está sobre una superficie
|
||||||
auto isOnConveyorBelt() -> bool; // Comprueba si el jugador esta sobre una cinta transportadora
|
auto isOnConveyorBelt() -> bool; // Comprueba si el jugador esta sobre una cinta transportadora
|
||||||
auto isOnSlope() -> bool; // Comprueba si el jugador está sobre una rampa
|
auto isOnSlope() -> bool; // Comprueba si el jugador está sobre una rampa
|
||||||
auto isLeftSlope() -> bool; // Comprueba si current_slope_ es una rampa izquierda (ascendente a la izquierda)
|
auto isLeftSlope() -> bool; // Comprueba si current_slope_ es una rampa izquierda (ascendente a la izquierda)
|
||||||
void updateCurrentSlope(); // Actualiza current_slope_ con la rampa correcta y muestra debug info
|
void updateCurrentSlope(); // Actualiza current_slope_ con la rampa correcta y muestra debug info
|
||||||
|
|
||||||
// --- Funciones de actualización de geometría ---
|
// --- Funciones de actualización de geometría ---
|
||||||
void syncSpriteAndCollider(); // Actualiza collider_box y collision points
|
void syncSpriteAndCollider(); // Actualiza collider_box y collision points
|
||||||
void updateColliderPoints(); // Actualiza los puntos de colisión
|
void updateColliderPoints(); // Actualiza los puntos de colisión
|
||||||
void updateFeet(); // Actualiza los puntos de los pies
|
void updateFeet(); // Actualiza los puntos de los pies
|
||||||
void placeSprite(); // Coloca el sprite en la posición del jugador
|
void placeSprite(); // Coloca el sprite en la posición del jugador
|
||||||
|
|
||||||
// --- Funciones de finalización ---
|
// --- Funciones de finalización ---
|
||||||
void animate(float delta_time); // Establece la animación del jugador
|
void animate(float delta_time); // Establece la animación del jugador
|
||||||
auto handleBorders() -> Room::Border; // Comprueba si se halla en alguno de los cuatro bordes
|
auto handleBorders() -> Room::Border; // Comprueba si se halla en alguno de los cuatro bordes
|
||||||
void handleJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
void handleJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
|
||||||
auto handleKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan
|
auto handleKillingTiles() -> bool; // Comprueba que el jugador no toque ningun tile de los que matan
|
||||||
void playJumpSound(float delta_time); // Calcula y reproduce el sonido de salto
|
void playJumpSound(float delta_time); // Calcula y reproduce el sonido de salto
|
||||||
void playFallSound(float delta_time); // Calcula y reproduce el sonido de caer
|
void playFallSound(float delta_time); // Calcula y reproduce el sonido de caer
|
||||||
void handleDeathByFalling(); // Gestiona la muerte al caer desde muy alto
|
void handleDeathByFalling(); // Gestiona la muerte al caer desde muy alto
|
||||||
void updateVelocity(); // Calcula la velocidad en x
|
void updateVelocity(); // Calcula la velocidad en x
|
||||||
void markAsDead(); // Marca al jugador como muerto
|
void markAsDead(); // Marca al jugador como muerto
|
||||||
};
|
};
|
||||||
@@ -5,51 +5,51 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class Cheevos {
|
class Cheevos {
|
||||||
public:
|
public:
|
||||||
// Tipos anidados (públicos porque se usan en la interfaz)
|
// Tipos anidados (públicos porque se usan en la interfaz)
|
||||||
struct Achievement {
|
struct Achievement {
|
||||||
int id{0}; // Identificador del logro
|
int id{0}; // Identificador del logro
|
||||||
std::string caption; // Texto con el nombre del logro
|
std::string caption; // Texto con el nombre del logro
|
||||||
std::string description; // Texto que describe el logro
|
std::string description; // Texto que describe el logro
|
||||||
int icon{0}; // Indice del icono a utilizar en la notificación
|
int icon{0}; // Indice del icono a utilizar en la notificación
|
||||||
bool completed{false}; // Indica si se ha obtenido el logro
|
bool completed{false}; // Indica si se ha obtenido el logro
|
||||||
bool obtainable{true}; // Indica si se puede obtener el logro
|
bool obtainable{true}; // Indica si se puede obtener el logro
|
||||||
};
|
};
|
||||||
|
|
||||||
using Achievements = std::vector<Achievement>; // Type alias para vector de logros
|
using Achievements = std::vector<Achievement>; // Type alias para vector de logros
|
||||||
|
|
||||||
// Gestión singleton
|
// Gestión singleton
|
||||||
static void init(const std::string& file); // Inicialización
|
static void init(const std::string& file); // Inicialización
|
||||||
static void destroy(); // Destrucción
|
static void destroy(); // Destrucción
|
||||||
static auto get() -> Cheevos*; // Acceso al singleton
|
static auto get() -> Cheevos*; // Acceso al singleton
|
||||||
|
|
||||||
// Gestión de logros
|
// Gestión de logros
|
||||||
void unlock(int id); // Desbloquea un logro
|
void unlock(int id); // Desbloquea un logro
|
||||||
void setUnobtainable(int id); // Invalida un logro
|
void setUnobtainable(int id); // Invalida un logro
|
||||||
void clearUnobtainableState(); // Elimina el estado "no obtenible"
|
void clearUnobtainableState(); // Elimina el estado "no obtenible"
|
||||||
void enable(bool value) { enabled_ = value; } // Habilita o deshabilita los logros
|
void enable(bool value) { enabled_ = value; } // Habilita o deshabilita los logros
|
||||||
|
|
||||||
// Consultas
|
// Consultas
|
||||||
[[nodiscard]] auto list() const -> const Achievements& { return cheevos_list_; } // Lista los logros
|
[[nodiscard]] auto list() const -> const Achievements& { return cheevos_list_; } // Lista los logros
|
||||||
auto getTotalUnlockedAchievements() -> int; // Devuelve logros desbloqueados
|
auto getTotalUnlockedAchievements() -> int; // Devuelve logros desbloqueados
|
||||||
auto size() -> int { return cheevos_list_.size(); } // Devuelve número total de logros
|
auto size() -> int { return cheevos_list_.size(); } // Devuelve número total de logros
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constantes singleton
|
// Constantes singleton
|
||||||
static Cheevos* cheevos; // [SINGLETON] Objeto privado
|
static Cheevos* cheevos; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
void init(); // Inicializa los logros
|
void init(); // Inicializa los logros
|
||||||
auto find(int id) -> int; // Busca un logro por id y devuelve el índice
|
auto find(int id) -> int; // Busca un logro por id y devuelve el índice
|
||||||
void loadFromFile(); // Carga el estado de los logros desde un fichero
|
void loadFromFile(); // Carga el estado de los logros desde un fichero
|
||||||
void saveToFile(); // Guarda el estado de los logros en un fichero
|
void saveToFile(); // Guarda el estado de los logros en un fichero
|
||||||
|
|
||||||
// Constructor y destructor privados [SINGLETON]
|
// Constructor y destructor privados [SINGLETON]
|
||||||
explicit Cheevos(std::string file);
|
explicit Cheevos(std::string file);
|
||||||
~Cheevos();
|
~Cheevos();
|
||||||
|
|
||||||
// Variables miembro
|
// Variables miembro
|
||||||
Achievements cheevos_list_; // Listado de logros
|
Achievements cheevos_list_; // Listado de logros
|
||||||
bool enabled_{true}; // Indica si los logros se pueden obtener
|
bool enabled_{true}; // Indica si los logros se pueden obtener
|
||||||
std::string file_; // Fichero donde leer/almacenar el estado de los logros
|
std::string file_; // Fichero donde leer/almacenar el estado de los logros
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,106 +16,106 @@
|
|||||||
* - Determinar tipo de tile en posiciones específicas
|
* - Determinar tipo de tile en posiciones específicas
|
||||||
*/
|
*/
|
||||||
class CollisionMap {
|
class CollisionMap {
|
||||||
public:
|
public:
|
||||||
// Enumeración de tipos de tile (para colisiones)
|
// Enumeración de tipos de tile (para colisiones)
|
||||||
enum class Tile {
|
enum class Tile {
|
||||||
EMPTY,
|
EMPTY,
|
||||||
WALL,
|
WALL,
|
||||||
PASSABLE,
|
PASSABLE,
|
||||||
SLOPE_L,
|
SLOPE_L,
|
||||||
SLOPE_R,
|
SLOPE_R,
|
||||||
KILL,
|
KILL,
|
||||||
ANIMATED
|
ANIMATED
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
* @param tile_map Vector con índices de tiles de la habitación
|
* @param tile_map Vector con índices de tiles de la habitación
|
||||||
* @param tile_set_width Ancho del tileset en tiles (para calcular tipo de tile)
|
* @param tile_set_width Ancho del tileset en tiles (para calcular tipo de tile)
|
||||||
* @param conveyor_belt_direction Dirección de las cintas transportadoras (-1, 0, +1)
|
* @param conveyor_belt_direction Dirección de las cintas transportadoras (-1, 0, +1)
|
||||||
*/
|
*/
|
||||||
CollisionMap(std::vector<int> tile_map, int tile_set_width, int conveyor_belt_direction);
|
CollisionMap(std::vector<int> tile_map, int tile_set_width, int conveyor_belt_direction);
|
||||||
~CollisionMap() = default;
|
~CollisionMap() = default;
|
||||||
|
|
||||||
// Prohibir copia y movimiento
|
// Prohibir copia y movimiento
|
||||||
CollisionMap(const CollisionMap&) = delete;
|
CollisionMap(const CollisionMap&) = delete;
|
||||||
auto operator=(const CollisionMap&) -> CollisionMap& = delete;
|
auto operator=(const CollisionMap&) -> CollisionMap& = delete;
|
||||||
CollisionMap(CollisionMap&&) = delete;
|
CollisionMap(CollisionMap&&) = delete;
|
||||||
auto operator=(CollisionMap&&) -> CollisionMap& = delete;
|
auto operator=(CollisionMap&&) -> CollisionMap& = delete;
|
||||||
|
|
||||||
// --- Queries de tipo de tile ---
|
// --- Queries de tipo de tile ---
|
||||||
[[nodiscard]] auto getTile(SDL_FPoint point) const -> Tile; // Devuelve el tipo de tile en un punto (pixel)
|
[[nodiscard]] auto getTile(SDL_FPoint point) const -> Tile; // Devuelve el tipo de tile en un punto (pixel)
|
||||||
[[nodiscard]] auto getTile(int index) const -> Tile; // Devuelve el tipo de tile en un índice del tilemap
|
[[nodiscard]] auto getTile(int index) const -> Tile; // Devuelve el tipo de tile en un índice del tilemap
|
||||||
|
|
||||||
// --- Queries de colisión con superficies ---
|
// --- Queries de colisión con superficies ---
|
||||||
auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes derechas (retorna X)
|
auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes derechas (retorna X)
|
||||||
auto checkLeftSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes izquierdas (retorna X)
|
auto checkLeftSurfaces(const SDL_FRect& rect) -> int; // Colisión con paredes izquierdas (retorna X)
|
||||||
auto checkTopSurfaces(const SDL_FRect& rect) -> int; // Colisión con techos (retorna Y)
|
auto checkTopSurfaces(const SDL_FRect& rect) -> int; // Colisión con techos (retorna Y)
|
||||||
auto checkTopSurfaces(const SDL_FPoint& p) -> bool; // Colisión punto con techos
|
auto checkTopSurfaces(const SDL_FPoint& p) -> bool; // Colisión punto con techos
|
||||||
auto checkBottomSurfaces(const SDL_FRect& rect) -> int; // Colisión con suelos (retorna Y)
|
auto checkBottomSurfaces(const SDL_FRect& rect) -> int; // Colisión con suelos (retorna Y)
|
||||||
|
|
||||||
// --- Queries de colisión con superficies automáticas (conveyor belts) ---
|
// --- Queries de colisión con superficies automáticas (conveyor belts) ---
|
||||||
auto checkAutoSurfaces(const SDL_FRect& rect) -> int; // Colisión con conveyor belts (retorna Y)
|
auto checkAutoSurfaces(const SDL_FRect& rect) -> int; // Colisión con conveyor belts (retorna Y)
|
||||||
auto checkConveyorBelts(const SDL_FPoint& p) -> bool; // Colisión punto con conveyor belts
|
auto checkConveyorBelts(const SDL_FPoint& p) -> bool; // Colisión punto con conveyor belts
|
||||||
|
|
||||||
// --- Queries de colisión con rampas ---
|
// --- Queries de colisión con rampas ---
|
||||||
auto checkLeftSlopes(const LineVertical& line) -> int; // Colisión línea con rampas izquierdas (retorna Y)
|
auto checkLeftSlopes(const LineVertical& line) -> int; // Colisión línea con rampas izquierdas (retorna Y)
|
||||||
auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas izquierdas
|
auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas izquierdas
|
||||||
auto checkRightSlopes(const LineVertical& line) -> int; // Colisión línea con rampas derechas (retorna Y)
|
auto checkRightSlopes(const LineVertical& line) -> int; // Colisión línea con rampas derechas (retorna Y)
|
||||||
auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas derechas
|
auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Colisión punto con rampas derechas
|
||||||
[[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto
|
[[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto
|
||||||
|
|
||||||
// --- Métodos estáticos ---
|
// --- Métodos estáticos ---
|
||||||
static auto getTileSize() -> int { return TILE_SIZE; } // Tamaño del tile en pixels
|
static auto getTileSize() -> int { return TILE_SIZE; } // Tamaño del tile en pixels
|
||||||
static auto getSlopeHeight(SDL_FPoint p, Tile slope) -> int; // Altura de rampa en un punto
|
static auto getSlopeHeight(SDL_FPoint p, Tile slope) -> int; // Altura de rampa en un punto
|
||||||
|
|
||||||
// --- Getters ---
|
// --- Getters ---
|
||||||
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; }
|
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; }
|
||||||
|
|
||||||
// Getters para debug visualization
|
// Getters para debug visualization
|
||||||
[[nodiscard]] auto getBottomFloors() const -> const std::vector<LineHorizontal>& { return bottom_floors_; }
|
[[nodiscard]] auto getBottomFloors() const -> const std::vector<LineHorizontal>& { return bottom_floors_; }
|
||||||
[[nodiscard]] auto getTopFloors() const -> const std::vector<LineHorizontal>& { return top_floors_; }
|
[[nodiscard]] auto getTopFloors() const -> const std::vector<LineHorizontal>& { return top_floors_; }
|
||||||
[[nodiscard]] auto getLeftWalls() const -> const std::vector<LineVertical>& { return left_walls_; }
|
[[nodiscard]] auto getLeftWalls() const -> const std::vector<LineVertical>& { return left_walls_; }
|
||||||
[[nodiscard]] auto getRightWalls() const -> const std::vector<LineVertical>& { return right_walls_; }
|
[[nodiscard]] auto getRightWalls() const -> const std::vector<LineVertical>& { return right_walls_; }
|
||||||
[[nodiscard]] auto getLeftSlopes() const -> const std::vector<LineDiagonal>& { return left_slopes_; }
|
[[nodiscard]] auto getLeftSlopes() const -> const std::vector<LineDiagonal>& { return left_slopes_; }
|
||||||
[[nodiscard]] auto getRightSlopes() const -> const std::vector<LineDiagonal>& { return right_slopes_; }
|
[[nodiscard]] auto getRightSlopes() const -> const std::vector<LineDiagonal>& { return right_slopes_; }
|
||||||
[[nodiscard]] auto getConveyorBeltFloors() const -> const std::vector<LineHorizontal>& { return conveyor_belt_floors_; }
|
[[nodiscard]] auto getConveyorBeltFloors() const -> const std::vector<LineHorizontal>& { return conveyor_belt_floors_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr int TILE_SIZE = 8; // Tamaño del tile en pixels
|
static constexpr int TILE_SIZE = 8; // Tamaño del tile en pixels
|
||||||
static constexpr int MAP_WIDTH = 32; // Ancho del mapa en tiles
|
static constexpr int MAP_WIDTH = 32; // Ancho del mapa en tiles
|
||||||
static constexpr int MAP_HEIGHT = 16; // Alto del mapa en tiles
|
static constexpr int MAP_HEIGHT = 16; // Alto del mapa en tiles
|
||||||
|
|
||||||
// --- Datos de la habitación ---
|
// --- Datos de la habitación ---
|
||||||
std::vector<int> tile_map_; // Índices de tiles de la habitación
|
std::vector<int> tile_map_; // Índices de tiles de la habitación
|
||||||
int tile_set_width_; // Ancho del tileset en tiles
|
int tile_set_width_; // Ancho del tileset en tiles
|
||||||
int conveyor_belt_direction_; // Dirección de conveyor belts
|
int conveyor_belt_direction_; // Dirección de conveyor belts
|
||||||
|
|
||||||
// --- Geometría de colisión ---
|
// --- Geometría de colisión ---
|
||||||
std::vector<LineHorizontal> bottom_floors_; // Superficies inferiores (suelos)
|
std::vector<LineHorizontal> bottom_floors_; // Superficies inferiores (suelos)
|
||||||
std::vector<LineHorizontal> top_floors_; // Superficies superiores (techos)
|
std::vector<LineHorizontal> top_floors_; // Superficies superiores (techos)
|
||||||
std::vector<LineVertical> left_walls_; // Paredes izquierdas
|
std::vector<LineVertical> left_walls_; // Paredes izquierdas
|
||||||
std::vector<LineVertical> right_walls_; // Paredes derechas
|
std::vector<LineVertical> right_walls_; // Paredes derechas
|
||||||
std::vector<LineDiagonal> left_slopes_; // Rampas que suben hacia la izquierda
|
std::vector<LineDiagonal> left_slopes_; // Rampas que suben hacia la izquierda
|
||||||
std::vector<LineDiagonal> right_slopes_; // Rampas que suben hacia la derecha
|
std::vector<LineDiagonal> right_slopes_; // Rampas que suben hacia la derecha
|
||||||
std::vector<LineHorizontal> conveyor_belt_floors_; // Superficies automáticas (conveyor belts)
|
std::vector<LineHorizontal> conveyor_belt_floors_; // Superficies automáticas (conveyor belts)
|
||||||
|
|
||||||
// --- Métodos privados de generación de geometría ---
|
// --- Métodos privados de generación de geometría ---
|
||||||
void initializeSurfaces(); // Inicializa todas las superficies de colisión
|
void initializeSurfaces(); // Inicializa todas las superficies de colisión
|
||||||
|
|
||||||
// Helpers para recopilar tiles
|
// Helpers para recopilar tiles
|
||||||
auto collectBottomTiles() -> std::vector<int>; // Tiles con superficie inferior
|
auto collectBottomTiles() -> std::vector<int>; // Tiles con superficie inferior
|
||||||
auto collectTopTiles() -> std::vector<int>; // Tiles con superficie superior
|
auto collectTopTiles() -> std::vector<int>; // Tiles con superficie superior
|
||||||
auto collectAnimatedTiles() -> std::vector<int>; // Tiles animados (conveyor belts)
|
auto collectAnimatedTiles() -> std::vector<int>; // Tiles animados (conveyor belts)
|
||||||
|
|
||||||
// Construcción de geometría
|
// Construcción de geometría
|
||||||
static void buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface);
|
static void buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface);
|
||||||
void setBottomSurfaces(); // Calcula superficies inferiores
|
void setBottomSurfaces(); // Calcula superficies inferiores
|
||||||
void setTopSurfaces(); // Calcula superficies superiores
|
void setTopSurfaces(); // Calcula superficies superiores
|
||||||
void setLeftSurfaces(); // Calcula paredes izquierdas
|
void setLeftSurfaces(); // Calcula paredes izquierdas
|
||||||
void setRightSurfaces(); // Calcula paredes derechas
|
void setRightSurfaces(); // Calcula paredes derechas
|
||||||
void setLeftSlopes(); // Calcula rampas izquierdas
|
void setLeftSlopes(); // Calcula rampas izquierdas
|
||||||
void setRightSlopes(); // Calcula rampas derechas
|
void setRightSlopes(); // Calcula rampas derechas
|
||||||
void setAutoSurfaces(); // Calcula conveyor belts
|
void setAutoSurfaces(); // Calcula conveyor belts
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,29 +17,29 @@ class Enemy;
|
|||||||
* - Detectar colisiones con enemigos
|
* - Detectar colisiones con enemigos
|
||||||
*/
|
*/
|
||||||
class EnemyManager {
|
class EnemyManager {
|
||||||
public:
|
public:
|
||||||
EnemyManager() = default;
|
EnemyManager() = default;
|
||||||
~EnemyManager() = default;
|
~EnemyManager() = default;
|
||||||
|
|
||||||
// Prohibir copia y movimiento para evitar duplicación accidental
|
// Prohibir copia y movimiento para evitar duplicación accidental
|
||||||
EnemyManager(const EnemyManager&) = delete;
|
EnemyManager(const EnemyManager&) = delete;
|
||||||
auto operator=(const EnemyManager&) -> EnemyManager& = delete;
|
auto operator=(const EnemyManager&) -> EnemyManager& = delete;
|
||||||
EnemyManager(EnemyManager&&) = delete;
|
EnemyManager(EnemyManager&&) = delete;
|
||||||
auto operator=(EnemyManager&&) -> EnemyManager& = delete;
|
auto operator=(EnemyManager&&) -> EnemyManager& = delete;
|
||||||
|
|
||||||
// Gestión de enemigos
|
// Gestión de enemigos
|
||||||
void addEnemy(std::shared_ptr<Enemy> enemy); // Añade un enemigo a la colección
|
void addEnemy(std::shared_ptr<Enemy> enemy); // Añade un enemigo a la colección
|
||||||
void clear(); // Elimina todos los enemigos
|
void clear(); // Elimina todos los enemigos
|
||||||
void removeLastEnemy(); // Elimina el último enemigo de la colección
|
void removeLastEnemy(); // Elimina el último enemigo de la colección
|
||||||
[[nodiscard]] auto isEmpty() const -> bool; // Comprueba si no hay enemigos
|
[[nodiscard]] auto isEmpty() const -> bool; // Comprueba si no hay enemigos
|
||||||
|
|
||||||
// Actualización y renderizado
|
// Actualización y renderizado
|
||||||
void update(float delta_time); // Actualiza todos los enemigos
|
void update(float delta_time); // Actualiza todos los enemigos
|
||||||
void render(); // Renderiza todos los enemigos
|
void render(); // Renderiza todos los enemigos
|
||||||
|
|
||||||
// Detección de colisiones
|
// Detección de colisiones
|
||||||
auto checkCollision(SDL_FRect& rect) -> bool; // Comprueba si hay colisión con algún enemigo
|
auto checkCollision(SDL_FRect& rect) -> bool; // Comprueba si hay colisión con algún enemigo
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<Enemy>> enemies_; // Colección de enemigos
|
std::vector<std::shared_ptr<Enemy>> enemies_; // Colección de enemigos
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,49 +21,49 @@ class Item;
|
|||||||
* - Integración con ItemTracker, Scoreboard y Audio
|
* - Integración con ItemTracker, Scoreboard y Audio
|
||||||
*/
|
*/
|
||||||
class ItemManager {
|
class ItemManager {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
* @param room_name Nombre de la habitación (para ItemTracker)
|
* @param room_name Nombre de la habitación (para ItemTracker)
|
||||||
* @param scoreboard_data Puntero compartido a los datos del scoreboard
|
* @param scoreboard_data Puntero compartido a los datos del scoreboard
|
||||||
*/
|
*/
|
||||||
ItemManager(std::string room_name, std::shared_ptr<Scoreboard::Data> scoreboard_data);
|
ItemManager(std::string room_name, std::shared_ptr<Scoreboard::Data> scoreboard_data);
|
||||||
~ItemManager() = default;
|
~ItemManager() = default;
|
||||||
|
|
||||||
// Prohibir copia y movimiento para evitar duplicación accidental
|
// Prohibir copia y movimiento para evitar duplicación accidental
|
||||||
ItemManager(const ItemManager&) = delete;
|
ItemManager(const ItemManager&) = delete;
|
||||||
auto operator=(const ItemManager&) -> ItemManager& = delete;
|
auto operator=(const ItemManager&) -> ItemManager& = delete;
|
||||||
ItemManager(ItemManager&&) = delete;
|
ItemManager(ItemManager&&) = delete;
|
||||||
auto operator=(ItemManager&&) -> ItemManager& = delete;
|
auto operator=(ItemManager&&) -> ItemManager& = delete;
|
||||||
|
|
||||||
// Gestión de items
|
// Gestión de items
|
||||||
void addItem(std::shared_ptr<Item> item); // Añade un item a la colección
|
void addItem(std::shared_ptr<Item> item); // Añade un item a la colección
|
||||||
void clear(); // Elimina todos los items
|
void clear(); // Elimina todos los items
|
||||||
|
|
||||||
// Actualización y renderizado
|
// Actualización y renderizado
|
||||||
void update(float delta_time); // Actualiza todos los items
|
void update(float delta_time); // Actualiza todos los items
|
||||||
void render(); // Renderiza todos los items
|
void render(); // Renderiza todos los items
|
||||||
|
|
||||||
// Estado
|
// Estado
|
||||||
void setPaused(bool paused); // Pausa/despausa todos los items
|
void setPaused(bool paused); // Pausa/despausa todos los items
|
||||||
|
|
||||||
// Detección de colisiones
|
// Detección de colisiones
|
||||||
/**
|
/**
|
||||||
* @brief Comprueba si hay colisión con algún item
|
* @brief Comprueba si hay colisión con algún item
|
||||||
*
|
*
|
||||||
* Si hay colisión:
|
* Si hay colisión:
|
||||||
* - Añade el item a ItemTracker
|
* - Añade el item a ItemTracker
|
||||||
* - Elimina el item de la colección
|
* - Elimina el item de la colección
|
||||||
* - Reproduce el sonido de pickup
|
* - Reproduce el sonido de pickup
|
||||||
* - Actualiza el scoreboard y estadísticas
|
* - Actualiza el scoreboard y estadísticas
|
||||||
*
|
*
|
||||||
* @param rect Rectángulo de colisión
|
* @param rect Rectángulo de colisión
|
||||||
* @return true si hubo colisión, false en caso contrario
|
* @return true si hubo colisión, false en caso contrario
|
||||||
*/
|
*/
|
||||||
auto checkCollision(SDL_FRect& rect) -> bool;
|
auto checkCollision(SDL_FRect& rect) -> bool;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<Item>> items_; // Colección de items
|
std::vector<std::shared_ptr<Item>> items_; // Colección de items
|
||||||
std::string room_name_; // Nombre de la habitación
|
std::string room_name_; // Nombre de la habitación
|
||||||
std::shared_ptr<Scoreboard::Data> data_; // Datos del scoreboard
|
std::shared_ptr<Scoreboard::Data> data_; // Datos del scoreboard
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,43 +7,43 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class ItemTracker {
|
class ItemTracker {
|
||||||
public:
|
public:
|
||||||
// Gestión singleton
|
// Gestión singleton
|
||||||
static void init(); // Inicialización
|
static void init(); // Inicialización
|
||||||
static void destroy(); // Destrucción
|
static void destroy(); // Destrucción
|
||||||
static auto get() -> ItemTracker*; // Acceso al singleton
|
static auto get() -> ItemTracker*; // Acceso al singleton
|
||||||
|
|
||||||
// Gestión de items
|
// Gestión de items
|
||||||
auto hasBeenPicked(const std::string& name, SDL_FPoint pos) -> bool; // Comprueba si el objeto ya ha sido cogido
|
auto hasBeenPicked(const std::string& name, SDL_FPoint pos) -> bool; // Comprueba si el objeto ya ha sido cogido
|
||||||
void addItem(const std::string& name, SDL_FPoint pos); // Añade el objeto a la lista
|
void addItem(const std::string& name, SDL_FPoint pos); // Añade el objeto a la lista
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Tipos anidados privados
|
// Tipos anidados privados
|
||||||
struct Data {
|
struct Data {
|
||||||
std::string name; // Nombre de la habitación donde se encuentra el objeto
|
std::string name; // Nombre de la habitación donde se encuentra el objeto
|
||||||
std::vector<SDL_FPoint> pos; // Lista de objetos cogidos de la habitación
|
std::vector<SDL_FPoint> pos; // Lista de objetos cogidos de la habitación
|
||||||
|
|
||||||
// Constructor para facilitar creación con posición inicial
|
// Constructor para facilitar creación con posición inicial
|
||||||
Data(std::string name, const SDL_FPoint& position)
|
Data(std::string name, const SDL_FPoint& position)
|
||||||
: name(std::move(name)) {
|
: name(std::move(name)) {
|
||||||
pos.push_back(position);
|
pos.push_back(position);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constantes privadas
|
// Constantes privadas
|
||||||
static constexpr int NOT_FOUND = -1; // Valor de retorno cuando no se encuentra un elemento
|
static constexpr int NOT_FOUND = -1; // Valor de retorno cuando no se encuentra un elemento
|
||||||
|
|
||||||
// Constantes singleton
|
// Constantes singleton
|
||||||
static ItemTracker* item_tracker; // [SINGLETON] Objeto privado
|
static ItemTracker* item_tracker; // [SINGLETON] Objeto privado
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
auto findByName(const std::string& name) -> int; // Busca una entrada en la lista por nombre
|
auto findByName(const std::string& name) -> int; // Busca una entrada en la lista por nombre
|
||||||
auto findByPos(int index, SDL_FPoint pos) -> int; // Busca una entrada en la lista por posición
|
auto findByPos(int index, SDL_FPoint pos) -> int; // Busca una entrada en la lista por posición
|
||||||
|
|
||||||
// Constructor y destructor privados [SINGLETON]
|
// Constructor y destructor privados [SINGLETON]
|
||||||
ItemTracker() = default;
|
ItemTracker() = default;
|
||||||
~ItemTracker() = default;
|
~ItemTracker() = default;
|
||||||
|
|
||||||
// Variables miembro
|
// Variables miembro
|
||||||
std::vector<Data> items_; // Lista con todos los objetos recogidos
|
std::vector<Data> items_; // Lista con todos los objetos recogidos
|
||||||
};
|
};
|
||||||
@@ -18,116 +18,116 @@ class CollisionMap;
|
|||||||
class TilemapRenderer;
|
class TilemapRenderer;
|
||||||
|
|
||||||
class Room {
|
class Room {
|
||||||
public:
|
public:
|
||||||
// -- Enumeraciones y estructuras ---
|
// -- Enumeraciones y estructuras ---
|
||||||
enum class Border : int {
|
enum class Border : int {
|
||||||
TOP = 0,
|
TOP = 0,
|
||||||
RIGHT = 1,
|
RIGHT = 1,
|
||||||
BOTTOM = 2,
|
BOTTOM = 2,
|
||||||
LEFT = 3,
|
LEFT = 3,
|
||||||
NONE = 4
|
NONE = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Tile {
|
enum class Tile {
|
||||||
EMPTY,
|
EMPTY,
|
||||||
WALL,
|
WALL,
|
||||||
PASSABLE,
|
PASSABLE,
|
||||||
SLOPE_L,
|
SLOPE_L,
|
||||||
SLOPE_R,
|
SLOPE_R,
|
||||||
KILL,
|
KILL,
|
||||||
ANIMATED
|
ANIMATED
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
std::string number; // Numero de la habitación
|
std::string number; // Numero de la habitación
|
||||||
std::string name; // Nombre de la habitación
|
std::string name; // Nombre de la habitación
|
||||||
std::string bg_color; // Color de fondo de la habitación
|
std::string bg_color; // Color de fondo de la habitación
|
||||||
std::string border_color; // Color del borde de la pantalla
|
std::string border_color; // Color del borde de la pantalla
|
||||||
std::string item_color1; // Color 1 para los items de la habitación
|
std::string item_color1; // Color 1 para los items de la habitación
|
||||||
std::string item_color2; // Color 2 para los items de la habitación
|
std::string item_color2; // Color 2 para los items de la habitación
|
||||||
std::string upper_room; // Identificador de la habitación que se encuentra arriba
|
std::string upper_room; // Identificador de la habitación que se encuentra arriba
|
||||||
std::string lower_room; // Identificador de la habitación que se encuentra abajo
|
std::string lower_room; // Identificador de la habitación que se encuentra abajo
|
||||||
std::string left_room; // Identificador de la habitación que se encuentra a la izquierda
|
std::string left_room; // Identificador de la habitación que se encuentra a la izquierda
|
||||||
std::string right_room; // Identificador de la habitación que se encuentra a la derecha
|
std::string right_room; // Identificador de la habitación que se encuentra a la derecha
|
||||||
std::string tile_set_file; // Imagen con los gráficos para la habitación
|
std::string tile_set_file; // Imagen con los gráficos para la habitación
|
||||||
int conveyor_belt_direction{0}; // Sentido en el que arrastran las superficies automáticas de la habitación
|
int conveyor_belt_direction{0}; // Sentido en el que arrastran las superficies automáticas de la habitación
|
||||||
std::vector<int> tile_map; // Índice de los tiles a dibujar en la habitación (embebido desde YAML)
|
std::vector<int> tile_map; // Índice de los tiles a dibujar en la habitación (embebido desde YAML)
|
||||||
std::vector<Enemy::Data> enemies; // Listado con los enemigos de la habitación
|
std::vector<Enemy::Data> enemies; // Listado con los enemigos de la habitación
|
||||||
std::vector<Item::Data> items; // Listado con los items que hay en la habitación
|
std::vector<Item::Data> items; // Listado con los items que hay en la habitación
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructor y destructor
|
// Constructor y destructor
|
||||||
Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data);
|
Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data);
|
||||||
~Room(); // Definido en .cpp para poder usar unique_ptr con forward declarations
|
~Room(); // Definido en .cpp para poder usar unique_ptr con forward declarations
|
||||||
|
|
||||||
// --- Funciones ---
|
// --- Funciones ---
|
||||||
[[nodiscard]] auto getName() const -> const std::string& { return name_; } // Devuelve el nombre de la habitación
|
[[nodiscard]] auto getName() const -> const std::string& { return name_; } // Devuelve el nombre de la habitación
|
||||||
[[nodiscard]] auto getBGColor() const -> Uint8 { return stringToColor(bg_color_); } // Devuelve el color de la habitación
|
[[nodiscard]] auto getBGColor() const -> Uint8 { return stringToColor(bg_color_); } // Devuelve el color de la habitación
|
||||||
[[nodiscard]] auto getBorderColor() const -> Uint8 { return stringToColor(border_color_); } // Devuelve el color del borde
|
[[nodiscard]] auto getBorderColor() const -> Uint8 { return stringToColor(border_color_); } // Devuelve el color del borde
|
||||||
void renderMap(); // Dibuja el mapa en pantalla
|
void renderMap(); // Dibuja el mapa en pantalla
|
||||||
void renderEnemies(); // Dibuja los enemigos en pantalla
|
void renderEnemies(); // Dibuja los enemigos en pantalla
|
||||||
void renderItems(); // Dibuja los objetos en pantalla
|
void renderItems(); // Dibuja los objetos en pantalla
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void redrawMap(); // Redibuja el mapa (para actualizar modo debug)
|
void redrawMap(); // Redibuja el mapa (para actualizar modo debug)
|
||||||
#endif
|
#endif
|
||||||
void update(float delta_time); // Actualiza las variables y objetos de la habitación
|
void update(float delta_time); // Actualiza las variables y objetos de la habitación
|
||||||
auto getRoom(Border border) -> std::string; // Devuelve la cadena del fichero de la habitación contigua segun el borde
|
auto getRoom(Border border) -> std::string; // Devuelve la cadena del fichero de la habitación contigua segun el borde
|
||||||
auto getTile(SDL_FPoint point) -> Tile; // Devuelve el tipo de tile que hay en ese pixel
|
auto getTile(SDL_FPoint point) -> Tile; // Devuelve el tipo de tile que hay en ese pixel
|
||||||
auto getTile(int index) -> Tile; // Devuelve el tipo de tile en un índice del tilemap
|
auto getTile(int index) -> Tile; // Devuelve el tipo de tile en un índice del tilemap
|
||||||
auto enemyCollision(SDL_FRect& rect) -> bool; // Indica si hay colision con un enemigo a partir de un rectangulo
|
auto enemyCollision(SDL_FRect& rect) -> bool; // Indica si hay colision con un enemigo a partir de un rectangulo
|
||||||
auto itemCollision(SDL_FRect& rect) -> bool; // Indica si hay colision con un objeto a partir de un rectangulo
|
auto itemCollision(SDL_FRect& rect) -> bool; // Indica si hay colision con un objeto a partir de un rectangulo
|
||||||
static auto getTileSize() -> int { return TILE_SIZE; } // Obten el tamaño del tile
|
static auto getTileSize() -> int { return TILE_SIZE; } // Obten el tamaño del tile
|
||||||
static auto getSlopeHeight(SDL_FPoint p, Tile slope) -> int; // Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile
|
static auto getSlopeHeight(SDL_FPoint p, Tile slope) -> int; // Obten la coordenada de la cuesta a partir de un punto perteneciente a ese tile
|
||||||
auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
auto checkRightSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
||||||
auto checkLeftSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
auto checkLeftSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
||||||
auto checkTopSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
auto checkTopSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
||||||
auto checkBottomSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
auto checkBottomSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
||||||
auto checkAutoSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
auto checkAutoSurfaces(const SDL_FRect& rect) -> int; // Comprueba las colisiones
|
||||||
auto checkTopSurfaces(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
auto checkTopSurfaces(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
||||||
auto checkConveyorBelts(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
auto checkConveyorBelts(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
||||||
auto checkLeftSlopes(const LineVertical& line) -> int; // Comprueba las colisiones
|
auto checkLeftSlopes(const LineVertical& line) -> int; // Comprueba las colisiones
|
||||||
auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
auto checkLeftSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
||||||
auto checkRightSlopes(const LineVertical& line) -> int; // Comprueba las colisiones
|
auto checkRightSlopes(const LineVertical& line) -> int; // Comprueba las colisiones
|
||||||
auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
auto checkRightSlopes(const SDL_FPoint& p) -> bool; // Comprueba las colisiones
|
||||||
[[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto
|
[[nodiscard]] auto getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal*; // Obtiene puntero a slope en un punto
|
||||||
void setPaused(bool value); // Pone el mapa en modo pausa
|
void setPaused(bool value); // Pone el mapa en modo pausa
|
||||||
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } // Obten la direccion de las superficies automaticas
|
[[nodiscard]] auto getConveyorBeltDirection() const -> int { return conveyor_belt_direction_; } // Obten la direccion de las superficies automaticas
|
||||||
|
|
||||||
// Método de carga de archivos YAML (delegado a RoomLoader)
|
// Método de carga de archivos YAML (delegado a RoomLoader)
|
||||||
static auto loadYAML(const std::string& file_path, bool verbose = false) -> Data; // Carga habitación desde archivo YAML unificado
|
static auto loadYAML(const std::string& file_path, bool verbose = false) -> Data; // Carga habitación desde archivo YAML unificado
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constantes
|
// Constantes
|
||||||
static constexpr int TILE_SIZE = 8; // Ancho del tile en pixels
|
static constexpr int TILE_SIZE = 8; // Ancho del tile en pixels
|
||||||
static constexpr int MAP_WIDTH = 32; // Ancho del mapa en tiles
|
static constexpr int MAP_WIDTH = 32; // Ancho del mapa en tiles
|
||||||
static constexpr int MAP_HEIGHT = 16; // Alto del mapa en tiles
|
static constexpr int MAP_HEIGHT = 16; // Alto del mapa en tiles
|
||||||
|
|
||||||
// Objetos y punteros
|
// Objetos y punteros
|
||||||
std::unique_ptr<EnemyManager> enemy_manager_; // Gestor de enemigos de la habitación
|
std::unique_ptr<EnemyManager> enemy_manager_; // Gestor de enemigos de la habitación
|
||||||
std::unique_ptr<ItemManager> item_manager_; // Gestor de items de la habitación
|
std::unique_ptr<ItemManager> item_manager_; // Gestor de items de la habitación
|
||||||
std::unique_ptr<CollisionMap> collision_map_; // Mapa de colisiones de la habitación
|
std::unique_ptr<CollisionMap> collision_map_; // Mapa de colisiones de la habitación
|
||||||
std::unique_ptr<TilemapRenderer> tilemap_renderer_; // Renderizador del mapa de tiles
|
std::unique_ptr<TilemapRenderer> tilemap_renderer_; // Renderizador del mapa de tiles
|
||||||
std::shared_ptr<Surface> surface_; // Textura con los graficos de la habitación
|
std::shared_ptr<Surface> surface_; // Textura con los graficos de la habitación
|
||||||
std::shared_ptr<Scoreboard::Data> data_; // Puntero a los datos del marcador
|
std::shared_ptr<Scoreboard::Data> data_; // Puntero a los datos del marcador
|
||||||
|
|
||||||
// --- Variables ---
|
// --- Variables ---
|
||||||
std::string number_; // Numero de la habitación
|
std::string number_; // Numero de la habitación
|
||||||
std::string name_; // Nombre de la habitación
|
std::string name_; // Nombre de la habitación
|
||||||
std::string bg_color_; // Color de fondo de la habitación
|
std::string bg_color_; // Color de fondo de la habitación
|
||||||
std::string border_color_; // Color del borde de la pantalla
|
std::string border_color_; // Color del borde de la pantalla
|
||||||
std::string item_color1_; // Color 1 para los items de la habitación
|
std::string item_color1_; // Color 1 para los items de la habitación
|
||||||
std::string item_color2_; // Color 2 para los items de la habitación
|
std::string item_color2_; // Color 2 para los items de la habitación
|
||||||
std::string upper_room_; // Identificador de la habitación que se encuentra arriba
|
std::string upper_room_; // Identificador de la habitación que se encuentra arriba
|
||||||
std::string lower_room_; // Identificador de la habitación que se encuentra abajp
|
std::string lower_room_; // Identificador de la habitación que se encuentra abajp
|
||||||
std::string left_room_; // Identificador de la habitación que se encuentra a la izquierda
|
std::string left_room_; // Identificador de la habitación que se encuentra a la izquierda
|
||||||
std::string right_room_; // Identificador de la habitación que se encuentra a la derecha
|
std::string right_room_; // Identificador de la habitación que se encuentra a la derecha
|
||||||
std::string tile_set_file_; // Imagen con los graficos para la habitación
|
std::string tile_set_file_; // Imagen con los graficos para la habitación
|
||||||
std::vector<int> tile_map_; // Indice de los tiles a dibujar en la habitación (embebido desde YAML)
|
std::vector<int> tile_map_; // Indice de los tiles a dibujar en la habitación (embebido desde YAML)
|
||||||
int conveyor_belt_direction_{0}; // Sentido en el que arrastran las superficies automáticas de la habitación
|
int conveyor_belt_direction_{0}; // Sentido en el que arrastran las superficies automáticas de la habitación
|
||||||
bool is_paused_{false}; // Indica si el mapa esta en modo pausa
|
bool is_paused_{false}; // Indica si el mapa esta en modo pausa
|
||||||
int tile_set_width_{0}; // Ancho del tileset en tiles
|
int tile_set_width_{0}; // Ancho del tileset en tiles
|
||||||
|
|
||||||
// --- Funciones ---
|
// --- Funciones ---
|
||||||
void initializeRoom(const Data& room); // Inicializa los valores
|
void initializeRoom(const Data& room); // Inicializa los valores
|
||||||
void openTheJail(); // Abre la jail para poder entrar
|
void openTheJail(); // Abre la jail para poder entrar
|
||||||
};
|
};
|
||||||
@@ -20,114 +20,114 @@
|
|||||||
* Esta clase contiene solo métodos estáticos y no debe instanciarse.
|
* Esta clase contiene solo métodos estáticos y no debe instanciarse.
|
||||||
*/
|
*/
|
||||||
class RoomLoader {
|
class RoomLoader {
|
||||||
public:
|
public:
|
||||||
// Constructor eliminado para prevenir instanciación
|
// Constructor eliminado para prevenir instanciación
|
||||||
RoomLoader() = delete;
|
RoomLoader() = delete;
|
||||||
~RoomLoader() = delete;
|
~RoomLoader() = delete;
|
||||||
RoomLoader(const RoomLoader&) = delete;
|
RoomLoader(const RoomLoader&) = delete;
|
||||||
auto operator=(const RoomLoader&) -> RoomLoader& = delete;
|
auto operator=(const RoomLoader&) -> RoomLoader& = delete;
|
||||||
RoomLoader(RoomLoader&&) = delete;
|
RoomLoader(RoomLoader&&) = delete;
|
||||||
auto operator=(RoomLoader&&) -> RoomLoader& = delete;
|
auto operator=(RoomLoader&&) -> RoomLoader& = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Carga un archivo de room en formato YAML
|
* @brief Carga un archivo de room en formato YAML
|
||||||
* @param file_path Ruta al archivo YAML de habitación
|
* @param file_path Ruta al archivo YAML de habitación
|
||||||
* @param verbose Si true, muestra información de debug
|
* @param verbose Si true, muestra información de debug
|
||||||
* @return Room::Data con todos los datos de la habitación incluyendo:
|
* @return Room::Data con todos los datos de la habitación incluyendo:
|
||||||
* - Configuración de la habitación (nombre, colores, etc.)
|
* - Configuración de la habitación (nombre, colores, etc.)
|
||||||
* - Tilemap completo (convertido de 2D a 1D)
|
* - Tilemap completo (convertido de 2D a 1D)
|
||||||
* - Lista de enemigos con todas sus propiedades
|
* - Lista de enemigos con todas sus propiedades
|
||||||
* - Lista de items con todas sus propiedades
|
* - Lista de items con todas sus propiedades
|
||||||
*
|
*
|
||||||
* El formato YAML esperado incluye:
|
* El formato YAML esperado incluye:
|
||||||
* - room: configuración general
|
* - room: configuración general
|
||||||
* - tilemap: array 2D de 16x32 tiles (convertido a vector 1D de 512 elementos)
|
* - tilemap: array 2D de 16x32 tiles (convertido a vector 1D de 512 elementos)
|
||||||
* - enemies: lista de enemigos (opcional)
|
* - enemies: lista de enemigos (opcional)
|
||||||
* - items: lista de items (opcional)
|
* - items: lista de items (opcional)
|
||||||
*/
|
*/
|
||||||
static auto loadYAML(const std::string& file_path, bool verbose = false) -> Room::Data;
|
static auto loadYAML(const std::string& file_path, bool verbose = false) -> Room::Data;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Convierte room connection de YAML a formato interno
|
* @brief Convierte room connection de YAML a formato interno
|
||||||
* @param value Valor del YAML (vacío, "02" o "02.yaml")
|
* @param value Valor del YAML (vacío, "02" o "02.yaml")
|
||||||
* @return "0" para sin conexión, o nombre del archivo con extensión
|
* @return "0" para sin conexión, o nombre del archivo con extensión
|
||||||
*/
|
*/
|
||||||
static auto convertRoomConnection(const std::string& value) -> std::string;
|
static auto convertRoomConnection(const std::string& value) -> std::string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convierte autoSurface de YAML a int
|
* @brief Convierte autoSurface de YAML a int
|
||||||
* @param node Nodo YAML (puede ser int o string "left"/"none"/"right")
|
* @param node Nodo YAML (puede ser int o string "left"/"none"/"right")
|
||||||
* @return -1 para left, 0 para none, 1 para right
|
* @return -1 para left, 0 para none, 1 para right
|
||||||
*/
|
*/
|
||||||
static auto convertAutoSurface(const fkyaml::node& node) -> int;
|
static auto convertAutoSurface(const fkyaml::node& node) -> int;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convierte un tilemap 2D a vector 1D flat
|
* @brief Convierte un tilemap 2D a vector 1D flat
|
||||||
* @param tilemap_2d Array 2D de tiles (16 rows × 32 cols)
|
* @param tilemap_2d Array 2D de tiles (16 rows × 32 cols)
|
||||||
* @return Vector 1D flat con 512 elementos
|
* @return Vector 1D flat con 512 elementos
|
||||||
*/
|
*/
|
||||||
static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>;
|
static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea la configuración general de la habitación
|
* @brief Parsea la configuración general de la habitación
|
||||||
* @param yaml Nodo raíz del YAML
|
* @param yaml Nodo raíz del YAML
|
||||||
* @param room Estructura de datos de la habitación a rellenar
|
* @param room Estructura de datos de la habitación a rellenar
|
||||||
* @param file_name Nombre del archivo para logging
|
* @param file_name Nombre del archivo para logging
|
||||||
*/
|
*/
|
||||||
static void parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name);
|
static void parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea las conexiones de la habitación (arriba/abajo/izq/der)
|
* @brief Parsea las conexiones de la habitación (arriba/abajo/izq/der)
|
||||||
* @param conn_node Nodo YAML con las conexiones
|
* @param conn_node Nodo YAML con las conexiones
|
||||||
* @param room Estructura de datos de la habitación a rellenar
|
* @param room Estructura de datos de la habitación a rellenar
|
||||||
*/
|
*/
|
||||||
static void parseRoomConnections(const fkyaml::node& conn_node, Room::Data& room);
|
static void parseRoomConnections(const fkyaml::node& conn_node, Room::Data& room);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea el tilemap de la habitación
|
* @brief Parsea el tilemap de la habitación
|
||||||
* @param yaml Nodo raíz del YAML
|
* @param yaml Nodo raíz del YAML
|
||||||
* @param room Estructura de datos de la habitación a rellenar
|
* @param room Estructura de datos de la habitación a rellenar
|
||||||
* @param file_name Nombre del archivo para logging
|
* @param file_name Nombre del archivo para logging
|
||||||
* @param verbose Si true, muestra información de debug
|
* @param verbose Si true, muestra información de debug
|
||||||
*/
|
*/
|
||||||
static void parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose);
|
static void parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea la lista de enemigos de la habitación
|
* @brief Parsea la lista de enemigos de la habitación
|
||||||
* @param yaml Nodo raíz del YAML
|
* @param yaml Nodo raíz del YAML
|
||||||
* @param room Estructura de datos de la habitación a rellenar
|
* @param room Estructura de datos de la habitación a rellenar
|
||||||
* @param verbose Si true, muestra información de debug
|
* @param verbose Si true, muestra información de debug
|
||||||
*/
|
*/
|
||||||
static void parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
static void parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea los datos de un enemigo individual
|
* @brief Parsea los datos de un enemigo individual
|
||||||
* @param enemy_node Nodo YAML del enemigo
|
* @param enemy_node Nodo YAML del enemigo
|
||||||
* @return Estructura Enemy::Data con los datos parseados
|
* @return Estructura Enemy::Data con los datos parseados
|
||||||
*/
|
*/
|
||||||
static auto parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data;
|
static auto parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea los límites de movimiento de un enemigo
|
* @brief Parsea los límites de movimiento de un enemigo
|
||||||
* @param bounds_node Nodo YAML con los límites
|
* @param bounds_node Nodo YAML con los límites
|
||||||
* @param enemy Estructura del enemigo a rellenar
|
* @param enemy Estructura del enemigo a rellenar
|
||||||
*/
|
*/
|
||||||
static void parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy);
|
static void parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea la lista de items de la habitación
|
* @brief Parsea la lista de items de la habitación
|
||||||
* @param yaml Nodo raíz del YAML
|
* @param yaml Nodo raíz del YAML
|
||||||
* @param room Estructura de datos de la habitación a rellenar
|
* @param room Estructura de datos de la habitación a rellenar
|
||||||
* @param verbose Si true, muestra información de debug
|
* @param verbose Si true, muestra información de debug
|
||||||
*/
|
*/
|
||||||
static void parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
static void parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parsea los datos de un item individual
|
* @brief Parsea los datos de un item individual
|
||||||
* @param item_node Nodo YAML del item
|
* @param item_node Nodo YAML del item
|
||||||
* @param room Datos de la habitación (para colores por defecto)
|
* @param room Datos de la habitación (para colores por defecto)
|
||||||
* @return Estructura Item::Data con los datos parseados
|
* @return Estructura Item::Data con los datos parseados
|
||||||
*/
|
*/
|
||||||
static auto parseItemData(const fkyaml::node& item_node, const Room::Data& room) -> Item::Data;
|
static auto parseItemData(const fkyaml::node& item_node, const Room::Data& room) -> Item::Data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class RoomTracker {
|
class RoomTracker {
|
||||||
public:
|
public:
|
||||||
RoomTracker() = default; // Constructor
|
RoomTracker() = default; // Constructor
|
||||||
~RoomTracker() = default; // Destructor
|
~RoomTracker() = default; // Destructor
|
||||||
|
|
||||||
auto addRoom(const std::string& name) -> bool; // Añade la habitación a la lista
|
auto addRoom(const std::string& name) -> bool; // Añade la habitación a la lista
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto hasBeenVisited(const std::string& name) -> bool; // Comprueba si ya ha sido visitada
|
auto hasBeenVisited(const std::string& name) -> bool; // Comprueba si ya ha sido visitada
|
||||||
|
|
||||||
std::vector<std::string> rooms_; // Lista con habitaciones visitadas
|
std::vector<std::string> rooms_; // Lista con habitaciones visitadas
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,59 +10,59 @@ class SurfaceAnimatedSprite; // lines 10-10
|
|||||||
class Surface; // lines 11-11
|
class Surface; // lines 11-11
|
||||||
|
|
||||||
class Scoreboard {
|
class Scoreboard {
|
||||||
public:
|
public:
|
||||||
// Tipos anidados
|
// Tipos anidados
|
||||||
struct Data {
|
struct Data {
|
||||||
int items{0}; // Lleva la cuenta de los objetos recogidos
|
int items{0}; // Lleva la cuenta de los objetos recogidos
|
||||||
int lives{0}; // Lleva la cuenta de las vidas restantes del jugador
|
int lives{0}; // Lleva la cuenta de las vidas restantes del jugador
|
||||||
int rooms{0}; // Lleva la cuenta de las habitaciones visitadas
|
int rooms{0}; // Lleva la cuenta de las habitaciones visitadas
|
||||||
bool music{true}; // Indica si ha de sonar la música durante el juego
|
bool music{true}; // Indica si ha de sonar la música durante el juego
|
||||||
Uint8 color{0}; // Color para escribir el texto del marcador
|
Uint8 color{0}; // Color para escribir el texto del marcador
|
||||||
Uint32 ini_clock{0}; // Tiempo inicial para calcular el tiempo transcurrido
|
Uint32 ini_clock{0}; // Tiempo inicial para calcular el tiempo transcurrido
|
||||||
bool jail_is_open{false}; // Indica si se puede entrar a la Jail
|
bool jail_is_open{false}; // Indica si se puede entrar a la Jail
|
||||||
};
|
};
|
||||||
|
|
||||||
// Métodos públicos
|
// Métodos públicos
|
||||||
explicit Scoreboard(std::shared_ptr<Data> data); // Constructor
|
explicit Scoreboard(std::shared_ptr<Data> data); // Constructor
|
||||||
~Scoreboard() = default; // Destructor
|
~Scoreboard() = default; // Destructor
|
||||||
void render(); // Pinta el objeto en pantalla
|
void render(); // Pinta el objeto en pantalla
|
||||||
void update(float delta_time); // Actualiza las variables del objeto
|
void update(float delta_time); // Actualiza las variables del objeto
|
||||||
void setPaused(bool value); // Pone el marcador en modo pausa
|
void setPaused(bool value); // Pone el marcador en modo pausa
|
||||||
auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
|
auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Tipos anidados
|
// Tipos anidados
|
||||||
struct ClockData {
|
struct ClockData {
|
||||||
int hours{0}; // Horas transcurridas
|
int hours{0}; // Horas transcurridas
|
||||||
int minutes{0}; // Minutos transcurridos
|
int minutes{0}; // Minutos transcurridos
|
||||||
int seconds{0}; // Segundos transcurridos
|
int seconds{0}; // Segundos transcurridos
|
||||||
std::string separator{":"}; // Separador para mostrar el tiempo
|
std::string separator{":"}; // Separador para mostrar el tiempo
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constantes de tiempo
|
// Constantes de tiempo
|
||||||
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; // Duración de cada estado del parpadeo (era 10 frames @ 60fps)
|
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; // Duración de cada estado del parpadeo (era 10 frames @ 60fps)
|
||||||
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
|
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
|
||||||
static constexpr int SPRITE_WALK_FRAMES = 4; // Número de frames de animación
|
static constexpr int SPRITE_WALK_FRAMES = 4; // Número de frames de animación
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida
|
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida
|
||||||
void updateItemsColor(float delta_time); // Actualiza el color de la cantidad de items recogidos
|
void updateItemsColor(float delta_time); // Actualiza el color de la cantidad de items recogidos
|
||||||
void fillTexture(); // Dibuja los elementos del marcador en la surface
|
void fillTexture(); // Dibuja los elementos del marcador en la surface
|
||||||
|
|
||||||
// Objetos y punteros
|
// Objetos y punteros
|
||||||
std::shared_ptr<SurfaceAnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador
|
std::shared_ptr<SurfaceAnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador
|
||||||
std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador
|
std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador
|
||||||
std::shared_ptr<Data> data_; // Contiene las variables a mostrar en el marcador
|
std::shared_ptr<Data> data_; // Contiene las variables a mostrar en el marcador
|
||||||
std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador
|
std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador
|
||||||
|
|
||||||
// Variables de estado
|
// Variables de estado
|
||||||
std::vector<Uint8> color_; // Vector con los colores del objeto
|
std::vector<Uint8> color_; // Vector con los colores del objeto
|
||||||
bool is_paused_{false}; // Indica si el marcador esta en modo pausa
|
bool is_paused_{false}; // Indica si el marcador esta en modo pausa
|
||||||
Uint32 paused_time_{0}; // Milisegundos que ha estado el marcador en pausa
|
Uint32 paused_time_{0}; // Milisegundos que ha estado el marcador en pausa
|
||||||
Uint32 paused_time_elapsed_{0}; // Tiempo acumulado en pausa
|
Uint32 paused_time_elapsed_{0}; // Tiempo acumulado en pausa
|
||||||
ClockData clock_{}; // Contiene las horas, minutos y segundos transcurridos desde el inicio de la partida
|
ClockData clock_{}; // Contiene las horas, minutos y segundos transcurridos desde el inicio de la partida
|
||||||
Uint8 items_color_{0}; // Color de la cantidad de items recogidos
|
Uint8 items_color_{0}; // Color de la cantidad de items recogidos
|
||||||
SDL_FRect surface_dest_{}; // Rectangulo donde dibujar la surface del marcador
|
SDL_FRect surface_dest_{}; // Rectangulo donde dibujar la surface del marcador
|
||||||
float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones
|
float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones
|
||||||
float items_color_timer_{0.0F}; // Timer para parpadeo de color de items
|
float items_color_timer_{0.0F}; // Timer para parpadeo de color de items
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,57 +4,57 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class Stats {
|
class Stats {
|
||||||
private:
|
private:
|
||||||
struct RoomData {
|
struct RoomData {
|
||||||
std::string name; // Nombre de la habitación
|
std::string name; // Nombre de la habitación
|
||||||
int visited; // Cuenta las veces que se ha visitado una habitación
|
int visited; // Cuenta las veces que se ha visitado una habitación
|
||||||
int died; // Cuenta las veces que se ha muerto en una habitación
|
int died; // Cuenta las veces que se ha muerto en una habitación
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dictionary {
|
struct Dictionary {
|
||||||
std::string number; // Numero de la habitación
|
std::string number; // Numero de la habitación
|
||||||
std::string name; // Nombre de la habitación
|
std::string name; // Nombre de la habitación
|
||||||
};
|
};
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
std::vector<Dictionary> dictionary_; // Lista con la equivalencia nombre-numero de habitacion
|
std::vector<Dictionary> dictionary_; // Lista con la equivalencia nombre-numero de habitacion
|
||||||
std::vector<RoomData> buffer_list_; // Lista con las estadisticas temporales por habitación
|
std::vector<RoomData> buffer_list_; // Lista con las estadisticas temporales por habitación
|
||||||
std::vector<RoomData> list_; // Lista con las estadisticas completas por habitación
|
std::vector<RoomData> list_; // Lista con las estadisticas completas por habitación
|
||||||
std::string buffer_path_; // Fichero con las estadísticas temporales
|
std::string buffer_path_; // Fichero con las estadísticas temporales
|
||||||
std::string file_path_; // Fichero con las estadísticas completas
|
std::string file_path_; // Fichero con las estadísticas completas
|
||||||
|
|
||||||
// Busca una entrada en la lista por nombre
|
// Busca una entrada en la lista por nombre
|
||||||
static auto findByName(const std::string& name, const std::vector<RoomData>& list) -> int;
|
static auto findByName(const std::string& name, const std::vector<RoomData>& list) -> int;
|
||||||
|
|
||||||
// Carga las estadisticas desde un fichero
|
// Carga las estadisticas desde un fichero
|
||||||
static auto loadFromFile(const std::string& file_path, std::vector<RoomData>& list) -> bool;
|
static auto loadFromFile(const std::string& file_path, std::vector<RoomData>& list) -> bool;
|
||||||
|
|
||||||
// Guarda las estadisticas en un fichero
|
// Guarda las estadisticas en un fichero
|
||||||
static void saveToFile(const std::string& file_path, const std::vector<RoomData>& list);
|
static void saveToFile(const std::string& file_path, const std::vector<RoomData>& list);
|
||||||
|
|
||||||
// Calcula cual es la habitación con más muertes
|
// Calcula cual es la habitación con más muertes
|
||||||
void checkWorstNightmare();
|
void checkWorstNightmare();
|
||||||
|
|
||||||
// Vuelca los datos del buffer en la lista de estadisticas
|
// Vuelca los datos del buffer en la lista de estadisticas
|
||||||
void updateListFromBuffer();
|
void updateListFromBuffer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructostd::string nst stdstd::string nst std::string& buffer);
|
// Constructostd::string nst stdstd::string nst std::string& buffer);
|
||||||
Stats(std::string file, std::string buffer);
|
Stats(std::string file, std::string buffer);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Stats();
|
~Stats();
|
||||||
|
|
||||||
// Inicializador
|
// Inicializador
|
||||||
// Se debe llamar a este procedimiento una vez se haya creado el diccionario numero-nombre
|
// Se debe llamar a este procedimiento una vez se haya creado el diccionario numero-nombre
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
// Añade una muerte a las estadisticas
|
// Añade una muerte a las estadisticas
|
||||||
void addDeath(const std::string& name);
|
void addDeath(const std::string& name);
|
||||||
|
|
||||||
// Añade una visita a las estadisticas
|
// Añade una visita a las estadisticas
|
||||||
void addVisit(const std::string& name);
|
void addVisit(const std::string& name);
|
||||||
|
|
||||||
// Añade una entrada al diccionario
|
// Añade una entrada al diccionario
|
||||||
void addDictionary(const std::string& number, const std::string& name);
|
void addDictionary(const std::string& number, const std::string& name);
|
||||||
};
|
};
|
||||||
@@ -22,97 +22,97 @@ class CollisionMap;
|
|||||||
* - Renderizar debug visualization (en modo DEBUG)
|
* - Renderizar debug visualization (en modo DEBUG)
|
||||||
*/
|
*/
|
||||||
class TilemapRenderer {
|
class TilemapRenderer {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
* @param tile_map Vector con índices de tiles de la habitación
|
* @param tile_map Vector con índices de tiles de la habitación
|
||||||
* @param tile_set_width Ancho del tileset en tiles
|
* @param tile_set_width Ancho del tileset en tiles
|
||||||
* @param tileset_surface Surface con los gráficos del tileset
|
* @param tileset_surface Surface con los gráficos del tileset
|
||||||
* @param bg_color Color de fondo de la habitación (como string)
|
* @param bg_color Color de fondo de la habitación (como string)
|
||||||
* @param conveyor_belt_direction Dirección de las cintas transportadoras (-1, 0, +1)
|
* @param conveyor_belt_direction Dirección de las cintas transportadoras (-1, 0, +1)
|
||||||
*/
|
*/
|
||||||
TilemapRenderer(std::vector<int> tile_map, int tile_set_width, std::shared_ptr<Surface> tileset_surface, std::string bg_color, int conveyor_belt_direction);
|
TilemapRenderer(std::vector<int> tile_map, int tile_set_width, std::shared_ptr<Surface> tileset_surface, std::string bg_color, int conveyor_belt_direction);
|
||||||
~TilemapRenderer() = default;
|
~TilemapRenderer() = default;
|
||||||
|
|
||||||
// Prohibir copia y movimiento
|
// Prohibir copia y movimiento
|
||||||
TilemapRenderer(const TilemapRenderer&) = delete;
|
TilemapRenderer(const TilemapRenderer&) = delete;
|
||||||
auto operator=(const TilemapRenderer&) -> TilemapRenderer& = delete;
|
auto operator=(const TilemapRenderer&) -> TilemapRenderer& = delete;
|
||||||
TilemapRenderer(TilemapRenderer&&) = delete;
|
TilemapRenderer(TilemapRenderer&&) = delete;
|
||||||
auto operator=(TilemapRenderer&&) -> TilemapRenderer& = delete;
|
auto operator=(TilemapRenderer&&) -> TilemapRenderer& = delete;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Inicializa el renderizador
|
* @brief Inicializa el renderizador
|
||||||
* @param collision_map Mapa de colisiones para determinar tiles animados
|
* @param collision_map Mapa de colisiones para determinar tiles animados
|
||||||
*
|
*
|
||||||
* Crea la textura del mapa, pinta los tiles estáticos, y localiza tiles animados
|
* Crea la textura del mapa, pinta los tiles estáticos, y localiza tiles animados
|
||||||
*/
|
*/
|
||||||
void initialize(const CollisionMap* collision_map);
|
void initialize(const CollisionMap* collision_map);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Actualiza las animaciones de tiles
|
* @brief Actualiza las animaciones de tiles
|
||||||
* @param delta_time Tiempo transcurrido desde el último frame (segundos)
|
* @param delta_time Tiempo transcurrido desde el último frame (segundos)
|
||||||
*/
|
*/
|
||||||
void update(float delta_time);
|
void update(float delta_time);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Renderiza el mapa completo en pantalla
|
* @brief Renderiza el mapa completo en pantalla
|
||||||
*
|
*
|
||||||
* Dibuja la textura del mapa y los tiles animados
|
* Dibuja la textura del mapa y los tiles animados
|
||||||
*/
|
*/
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
/**
|
/**
|
||||||
* @brief Redibuja el tilemap (para actualizar modo debug)
|
* @brief Redibuja el tilemap (para actualizar modo debug)
|
||||||
* @param collision_map Mapa de colisiones para dibujar líneas de debug
|
* @param collision_map Mapa de colisiones para dibujar líneas de debug
|
||||||
*
|
*
|
||||||
* Llamado cuando se activa/desactiva el modo debug para actualizar la visualización
|
* Llamado cuando se activa/desactiva el modo debug para actualizar la visualización
|
||||||
*/
|
*/
|
||||||
void redrawMap(const CollisionMap* collision_map);
|
void redrawMap(const CollisionMap* collision_map);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Activa/desactiva modo pausa
|
* @brief Activa/desactiva modo pausa
|
||||||
* @param paused true para pausar, false para reanudar
|
* @param paused true para pausar, false para reanudar
|
||||||
*
|
*
|
||||||
* Nota: Actualmente no afecta al renderizado, pero mantiene consistencia con Room
|
* Nota: Actualmente no afecta al renderizado, pero mantiene consistencia con Room
|
||||||
*/
|
*/
|
||||||
void setPaused(bool paused) { is_paused_ = paused; }
|
void setPaused(bool paused) { is_paused_ = paused; }
|
||||||
|
|
||||||
// Getter para la surface del mapa (usado por Room para acceso directo si es necesario)
|
// Getter para la surface del mapa (usado por Room para acceso directo si es necesario)
|
||||||
[[nodiscard]] auto getMapSurface() const -> std::shared_ptr<Surface> { return map_surface_; }
|
[[nodiscard]] auto getMapSurface() const -> std::shared_ptr<Surface> { return map_surface_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Estructura para tiles animados (conveyor belts)
|
// Estructura para tiles animados (conveyor belts)
|
||||||
struct AnimatedTile {
|
struct AnimatedTile {
|
||||||
std::shared_ptr<SurfaceSprite> sprite{nullptr}; // SurfaceSprite para dibujar el tile
|
std::shared_ptr<SurfaceSprite> sprite{nullptr}; // SurfaceSprite para dibujar el tile
|
||||||
int x_orig{0}; // Posición X del primer tile de la animación en tilesheet
|
int x_orig{0}; // Posición X del primer tile de la animación en tilesheet
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Constantes ===
|
// === Constantes ===
|
||||||
static constexpr int TILE_SIZE = Tile::SIZE; // Ancho del tile en pixels
|
static constexpr int TILE_SIZE = Tile::SIZE; // Ancho del tile en pixels
|
||||||
static constexpr int MAP_WIDTH = PlayArea::WIDTH / Tile::SIZE; // Ancho del mapa en tiles
|
static constexpr int MAP_WIDTH = PlayArea::WIDTH / Tile::SIZE; // Ancho del mapa en tiles
|
||||||
static constexpr int MAP_HEIGHT = PlayArea::HEIGHT / Tile::SIZE; // Alto del mapa en tiles
|
static constexpr int MAP_HEIGHT = PlayArea::HEIGHT / Tile::SIZE; // Alto del mapa en tiles
|
||||||
static constexpr int PLAY_AREA_WIDTH = PlayArea::WIDTH; // Ancho del área de juego en pixels
|
static constexpr int PLAY_AREA_WIDTH = PlayArea::WIDTH; // Ancho del área de juego en pixels
|
||||||
static constexpr int PLAY_AREA_HEIGHT = PlayArea::HEIGHT; // Alto del área de juego en pixels
|
static constexpr int PLAY_AREA_HEIGHT = PlayArea::HEIGHT; // Alto del área de juego en pixels
|
||||||
static constexpr float CONVEYOR_FRAME_DURATION = 0.05F; // Duración de cada frame (3 frames @ 60fps)
|
static constexpr float CONVEYOR_FRAME_DURATION = 0.05F; // Duración de cada frame (3 frames @ 60fps)
|
||||||
|
|
||||||
// === Datos de la habitación ===
|
// === Datos de la habitación ===
|
||||||
std::vector<int> tile_map_; // Índices de tiles de la habitación
|
std::vector<int> tile_map_; // Índices de tiles de la habitación
|
||||||
int tile_set_width_; // Ancho del tileset en tiles
|
int tile_set_width_; // Ancho del tileset en tiles
|
||||||
std::shared_ptr<Surface> tileset_surface_; // Gráficos del tileset
|
std::shared_ptr<Surface> tileset_surface_; // Gráficos del tileset
|
||||||
std::string bg_color_; // Color de fondo
|
std::string bg_color_; // Color de fondo
|
||||||
int conveyor_belt_direction_; // Dirección de conveyor belts
|
int conveyor_belt_direction_; // Dirección de conveyor belts
|
||||||
|
|
||||||
// === Renderizado ===
|
// === Renderizado ===
|
||||||
std::shared_ptr<Surface> map_surface_; // Textura para el mapa de la habitación
|
std::shared_ptr<Surface> map_surface_; // Textura para el mapa de la habitación
|
||||||
std::vector<AnimatedTile> animated_tiles_; // Tiles animados (conveyor belts)
|
std::vector<AnimatedTile> animated_tiles_; // Tiles animados (conveyor belts)
|
||||||
float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones
|
float time_accumulator_{0.0F}; // Acumulador de tiempo para animaciones
|
||||||
bool is_paused_{false}; // Indica si está en modo pausa
|
bool is_paused_{false}; // Indica si está en modo pausa
|
||||||
|
|
||||||
// === Métodos privados ===
|
// === Métodos privados ===
|
||||||
void fillMapTexture(const CollisionMap* collision_map); // Pinta el mapa estático y debug lines
|
void fillMapTexture(const CollisionMap* collision_map); // Pinta el mapa estático y debug lines
|
||||||
void setAnimatedTiles(const CollisionMap* collision_map); // Localiza todos los tiles animados
|
void setAnimatedTiles(const CollisionMap* collision_map); // Localiza todos los tiles animados
|
||||||
void updateAnimatedTiles(); // Actualiza tiles animados
|
void updateAnimatedTiles(); // Actualiza tiles animados
|
||||||
void renderAnimatedTiles(); // Renderiza tiles animados
|
void renderAnimatedTiles(); // Renderiza tiles animados
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,22 +15,22 @@
|
|||||||
// --- Namespace Options: gestión de configuración y opciones del juego ---
|
// --- Namespace Options: gestión de configuración y opciones del juego ---
|
||||||
namespace Options {
|
namespace Options {
|
||||||
|
|
||||||
// Estructura para las opciones de control de teclado
|
// Estructura para las opciones de control de teclado
|
||||||
struct KeyboardControls {
|
struct KeyboardControls {
|
||||||
SDL_Scancode key_left{Defaults::Controls::KEY_LEFT}; // Tecla para mover a la izquierda
|
SDL_Scancode key_left{Defaults::Controls::KEY_LEFT}; // Tecla para mover a la izquierda
|
||||||
SDL_Scancode key_right{Defaults::Controls::KEY_RIGHT}; // Tecla para mover a la derecha
|
SDL_Scancode key_right{Defaults::Controls::KEY_RIGHT}; // Tecla para mover a la derecha
|
||||||
SDL_Scancode key_jump{Defaults::Controls::KEY_JUMP}; // Tecla para saltar
|
SDL_Scancode key_jump{Defaults::Controls::KEY_JUMP}; // Tecla para saltar
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de control del gamepad/joystick
|
// Estructura para las opciones de control del gamepad/joystick
|
||||||
struct GamepadControls {
|
struct GamepadControls {
|
||||||
int button_left{Defaults::Controls::GAMEPAD_BUTTON_LEFT}; // Botón para mover a la izquierda (por defecto: DPAD_LEFT)
|
int button_left{Defaults::Controls::GAMEPAD_BUTTON_LEFT}; // Botón para mover a la izquierda (por defecto: DPAD_LEFT)
|
||||||
int button_right{Defaults::Controls::GAMEPAD_BUTTON_RIGHT}; // Botón para mover a la derecha (por defecto: DPAD_RIGHT)
|
int button_right{Defaults::Controls::GAMEPAD_BUTTON_RIGHT}; // Botón para mover a la derecha (por defecto: DPAD_RIGHT)
|
||||||
int button_jump{Defaults::Controls::GAMEPAD_BUTTON_JUMP}; // Botón para saltar (por defecto: WEST/X button)
|
int button_jump{Defaults::Controls::GAMEPAD_BUTTON_JUMP}; // Botón para saltar (por defecto: WEST/X button)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para albergar trucos
|
// Estructura para albergar trucos
|
||||||
struct Cheat {
|
struct Cheat {
|
||||||
enum class State : bool {
|
enum class State : bool {
|
||||||
DISABLED = false,
|
DISABLED = false,
|
||||||
ENABLED = true
|
ENABLED = true
|
||||||
@@ -45,38 +45,38 @@ struct Cheat {
|
|||||||
[[nodiscard]] auto enabled() const -> bool {
|
[[nodiscard]] auto enabled() const -> bool {
|
||||||
return infinite_lives == State::ENABLED || invincible == State::ENABLED || jail_is_open == State::ENABLED;
|
return infinite_lives == State::ENABLED || invincible == State::ENABLED || jail_is_open == State::ENABLED;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para almacenar estadísticas
|
// Estructura para almacenar estadísticas
|
||||||
struct Stats {
|
struct Stats {
|
||||||
int rooms{Defaults::Stats::ROOMS}; // Cantidad de habitaciones visitadas
|
int rooms{Defaults::Stats::ROOMS}; // Cantidad de habitaciones visitadas
|
||||||
int items{Defaults::Stats::ITEMS}; // Cantidad de items obtenidos
|
int items{Defaults::Stats::ITEMS}; // Cantidad de items obtenidos
|
||||||
std::string worst_nightmare{Defaults::Stats::WORST_NIGHTMARE}; // Habitación con más muertes acumuladas
|
std::string worst_nightmare{Defaults::Stats::WORST_NIGHTMARE}; // Habitación con más muertes acumuladas
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para el modo kiosko
|
// Estructura para el modo kiosko
|
||||||
struct Kiosk {
|
struct Kiosk {
|
||||||
bool enabled{Defaults::Kiosk::ENABLED}; // Indica si el modo kiosko está activo
|
bool enabled{Defaults::Kiosk::ENABLED}; // Indica si el modo kiosko está activo
|
||||||
std::string text{Defaults::Kiosk::TEXT}; // Texto a mostrar en el modo kiosko
|
std::string text{Defaults::Kiosk::TEXT}; // Texto a mostrar en el modo kiosko
|
||||||
bool infinite_lives{Defaults::Kiosk::INFINITE_LIVES}; // Indica si el jugador tiene vidas infinitas en modo kiosko
|
bool infinite_lives{Defaults::Kiosk::INFINITE_LIVES}; // Indica si el jugador tiene vidas infinitas en modo kiosko
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura con opciones de la ventana
|
// Estructura con opciones de la ventana
|
||||||
struct Window {
|
struct Window {
|
||||||
std::string caption{Texts::WINDOW_CAPTION}; // Texto que aparece en la barra de título de la ventana
|
std::string caption{Texts::WINDOW_CAPTION}; // Texto que aparece en la barra de título de la ventana
|
||||||
int zoom{Defaults::Window::ZOOM}; // Zoom de la ventana
|
int zoom{Defaults::Window::ZOOM}; // Zoom de la ventana
|
||||||
int max_zoom{Defaults::Window::ZOOM}; // Máximo tamaño de zoom para la ventana
|
int max_zoom{Defaults::Window::ZOOM}; // Máximo tamaño de zoom para la ventana
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para gestionar el borde de la pantalla
|
// Estructura para gestionar el borde de la pantalla
|
||||||
struct Border {
|
struct Border {
|
||||||
bool enabled{Defaults::Border::ENABLED}; // Indica si se ha de mostrar el borde
|
bool enabled{Defaults::Border::ENABLED}; // Indica si se ha de mostrar el borde
|
||||||
float width{Defaults::Border::WIDTH}; // Ancho del borde
|
float width{Defaults::Border::WIDTH}; // Ancho del borde
|
||||||
float height{Defaults::Border::HEIGHT}; // Alto del borde
|
float height{Defaults::Border::HEIGHT}; // Alto del borde
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de video
|
// Estructura para las opciones de video
|
||||||
struct Video {
|
struct Video {
|
||||||
bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa
|
bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa
|
||||||
Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen
|
Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen
|
||||||
bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no
|
bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no
|
||||||
@@ -86,36 +86,36 @@ struct Video {
|
|||||||
Border border{}; // Borde de la pantalla
|
Border border{}; // Borde de la pantalla
|
||||||
std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego
|
std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego
|
||||||
std::string info; // Información sobre el modo de vídeo
|
std::string info; // Información sobre el modo de vídeo
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de musica
|
// Estructura para las opciones de musica
|
||||||
struct Music {
|
struct Music {
|
||||||
bool enabled{Defaults::Music::ENABLED}; // Indica si la música suena o no
|
bool enabled{Defaults::Music::ENABLED}; // Indica si la música suena o no
|
||||||
float volume{Defaults::Music::VOLUME}; // Volumen al que suena la música
|
float volume{Defaults::Music::VOLUME}; // Volumen al que suena la música
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de sonido
|
// Estructura para las opciones de sonido
|
||||||
struct Sound {
|
struct Sound {
|
||||||
bool enabled{Defaults::Sound::ENABLED}; // Indica si los sonidos suenan o no
|
bool enabled{Defaults::Sound::ENABLED}; // Indica si los sonidos suenan o no
|
||||||
float volume{Defaults::Sound::VOLUME}; // Volumen al que suenan los sonidos (0 a 128 internamente)
|
float volume{Defaults::Sound::VOLUME}; // Volumen al que suenan los sonidos (0 a 128 internamente)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de audio
|
// Estructura para las opciones de audio
|
||||||
struct Audio {
|
struct Audio {
|
||||||
Music music{}; // Opciones para la música
|
Music music{}; // Opciones para la música
|
||||||
Sound sound{}; // Opciones para los efectos de sonido
|
Sound sound{}; // Opciones para los efectos de sonido
|
||||||
bool enabled{Defaults::Audio::ENABLED}; // Indica si el audio está activo o no
|
bool enabled{Defaults::Audio::ENABLED}; // Indica si el audio está activo o no
|
||||||
float volume{Defaults::Audio::VOLUME}; // Volumen al que suenan el audio (0-128 internamente)
|
float volume{Defaults::Audio::VOLUME}; // Volumen al que suenan el audio (0-128 internamente)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de juego
|
// Estructura para las opciones de juego
|
||||||
struct Game {
|
struct Game {
|
||||||
float width{Defaults::Canvas::WIDTH}; // Ancho de la resolucion del juego
|
float width{Defaults::Canvas::WIDTH}; // Ancho de la resolucion del juego
|
||||||
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
|
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para un preset de PostFX
|
// Estructura para un preset de PostFX
|
||||||
struct PostFXPreset {
|
struct PostFXPreset {
|
||||||
std::string name; // Nombre del preset
|
std::string name; // Nombre del preset
|
||||||
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
|
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
|
||||||
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
|
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
|
||||||
@@ -124,36 +124,36 @@ struct PostFXPreset {
|
|||||||
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
|
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
|
||||||
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
|
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
|
||||||
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
|
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Variables globales ---
|
// --- Variables globales ---
|
||||||
inline std::string version{}; // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles
|
inline std::string version{}; // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles
|
||||||
inline bool console{false}; // Indica si ha de mostrar información por la consola de texto
|
inline bool console{false}; // Indica si ha de mostrar información por la consola de texto
|
||||||
inline Cheat cheats{}; // Contiene trucos y ventajas para el juego
|
inline Cheat cheats{}; // Contiene trucos y ventajas para el juego
|
||||||
inline Game game{}; // Opciones de juego
|
inline Game game{}; // Opciones de juego
|
||||||
inline Video video{}; // Opciones de video
|
inline Video video{}; // Opciones de video
|
||||||
inline Stats stats{}; // Datos con las estadisticas de juego
|
inline Stats stats{}; // Datos con las estadisticas de juego
|
||||||
inline Window window{}; // Opciones relativas a la ventana
|
inline Window window{}; // Opciones relativas a la ventana
|
||||||
inline Audio audio{}; // Opciones relativas al audio
|
inline Audio audio{}; // Opciones relativas al audio
|
||||||
inline KeyboardControls keyboard_controls{}; // Teclas usadas para jugar
|
inline KeyboardControls keyboard_controls{}; // Teclas usadas para jugar
|
||||||
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
|
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
|
||||||
inline Kiosk kiosk{}; // Opciones del modo kiosko
|
inline Kiosk kiosk{}; // Opciones del modo kiosko
|
||||||
|
|
||||||
// Ruta completa del fichero de configuración (establecida mediante setConfigFile)
|
// Ruta completa del fichero de configuración (establecida mediante setConfigFile)
|
||||||
inline std::string config_file_path{};
|
inline std::string config_file_path{};
|
||||||
|
|
||||||
// --- Variables PostFX ---
|
// --- Variables PostFX ---
|
||||||
inline std::vector<PostFXPreset> postfx_presets{}; // Lista de presets de PostFX
|
inline std::vector<PostFXPreset> postfx_presets{}; // Lista de presets de PostFX
|
||||||
inline int current_postfx_preset{0}; // Índice del preset de PostFX actual
|
inline int current_postfx_preset{0}; // Índice del preset de PostFX actual
|
||||||
inline std::string postfx_file_path{}; // Ruta del fichero postfx.yaml
|
inline std::string postfx_file_path{}; // Ruta del fichero postfx.yaml
|
||||||
|
|
||||||
// --- Funciones públicas ---
|
// --- Funciones públicas ---
|
||||||
void init(); // Crea e inicializa las opciones del programa
|
void init(); // Crea e inicializa las opciones del programa
|
||||||
void setConfigFile(const std::string& path); // Establece la ruta del fichero de configuración
|
void setConfigFile(const std::string& path); // Establece la ruta del fichero de configuración
|
||||||
auto loadFromFile() -> bool; // Carga las opciones desde el fichero configurado
|
auto loadFromFile() -> bool; // Carga las opciones desde el fichero configurado
|
||||||
auto saveToFile() -> bool; // Guarda las opciones al fichero configurado
|
auto saveToFile() -> bool; // Guarda las opciones al fichero configurado
|
||||||
void setPostFXFile(const std::string& path); // Establece la ruta del fichero de PostFX
|
void setPostFXFile(const std::string& path); // Establece la ruta del fichero de PostFX
|
||||||
auto loadPostFXFromFile() -> bool; // Carga los presets de PostFX desde el fichero
|
auto loadPostFXFromFile() -> bool; // Carga los presets de PostFX desde el fichero
|
||||||
auto savePostFXToFile() -> bool; // Guarda los presets de PostFX por defecto
|
auto savePostFXToFile() -> bool; // Guarda los presets de PostFX por defecto
|
||||||
|
|
||||||
} // namespace Options
|
} // namespace Options
|
||||||
@@ -9,36 +9,36 @@
|
|||||||
|
|
||||||
namespace SceneManager {
|
namespace SceneManager {
|
||||||
|
|
||||||
// --- Escenas del programa ---
|
// --- Escenas del programa ---
|
||||||
enum class Scene {
|
enum class Scene {
|
||||||
LOGO, // Pantalla del logo
|
LOGO, // Pantalla del logo
|
||||||
LOADING_SCREEN, // Pantalla de carga
|
LOADING_SCREEN, // Pantalla de carga
|
||||||
TITLE, // Pantalla de título/menú principal
|
TITLE, // Pantalla de título/menú principal
|
||||||
CREDITS, // Créditos del juego
|
CREDITS, // Créditos del juego
|
||||||
GAME, // Juego principal
|
GAME, // Juego principal
|
||||||
DEMO, // Modo demostración
|
DEMO, // Modo demostración
|
||||||
GAME_OVER, // Pantalla de game over
|
GAME_OVER, // Pantalla de game over
|
||||||
ENDING, // Final del juego (ending 1)
|
ENDING, // Final del juego (ending 1)
|
||||||
ENDING2, // Final del juego (ending 2)
|
ENDING2, // Final del juego (ending 2)
|
||||||
QUIT // Salir del programa
|
QUIT // Salir del programa
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones para transiciones entre escenas ---
|
// --- Opciones para transiciones entre escenas ---
|
||||||
enum class Options {
|
enum class Options {
|
||||||
NONE, // Sin opciones especiales
|
NONE, // Sin opciones especiales
|
||||||
LOGO_TO_LOADING_SCREEN, // Del logo a la intro
|
LOGO_TO_LOADING_SCREEN, // Del logo a la intro
|
||||||
LOGO_TO_TITLE, // Del logo al título
|
LOGO_TO_TITLE, // Del logo al título
|
||||||
TITLE_WITH_LOADING_SCREEN, // Al título mostrando pantalla de carga
|
TITLE_WITH_LOADING_SCREEN, // Al título mostrando pantalla de carga
|
||||||
TITLE_WITHOUT_LOADING_SCREEN // Al título sin pantalla de carga
|
TITLE_WITHOUT_LOADING_SCREEN // Al título sin pantalla de carga
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Variables de estado globales ---
|
// --- Variables de estado globales ---
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
inline Scene current = Scene::GAME; // Escena actual
|
inline Scene current = Scene::GAME; // Escena actual
|
||||||
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
|
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
|
||||||
#else
|
#else
|
||||||
inline Scene current = Scene::LOGO; // Escena actual
|
inline Scene current = Scene::LOGO; // Escena actual
|
||||||
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
|
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace SceneManager
|
} // namespace SceneManager
|
||||||
|
|||||||
@@ -11,70 +11,70 @@ class PixelReveal;
|
|||||||
class DeltaTimer;
|
class DeltaTimer;
|
||||||
|
|
||||||
class Credits {
|
class Credits {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Credits();
|
Credits();
|
||||||
~Credits();
|
~Credits();
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Tipos anidados ---
|
// --- Tipos anidados ---
|
||||||
enum class State {
|
enum class State {
|
||||||
REVEALING_TEXT,
|
REVEALING_TEXT,
|
||||||
PAUSE_1,
|
PAUSE_1,
|
||||||
REVEALING_TEXT_2,
|
REVEALING_TEXT_2,
|
||||||
PAUSE_2,
|
PAUSE_2,
|
||||||
REVEALING_TEXT_3,
|
REVEALING_TEXT_3,
|
||||||
PAUSE_3,
|
PAUSE_3,
|
||||||
DISPLAYING_WITH_SHINE,
|
DISPLAYING_WITH_SHINE,
|
||||||
FADING_OUT,
|
FADING_OUT,
|
||||||
EXITING
|
EXITING
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Captions {
|
struct Captions {
|
||||||
std::string label; // Texto a escribir
|
std::string label; // Texto a escribir
|
||||||
Uint8 color{0}; // Color del texto
|
Uint8 color{0}; // Color del texto
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de tiempo (basado en 60 FPS) ---
|
// --- Constantes de tiempo (basado en 60 FPS) ---
|
||||||
static constexpr float REVEAL_PHASE_1_DURATION = 3.733F; // 224 frames @ 60fps
|
static constexpr float REVEAL_PHASE_1_DURATION = 3.733F; // 224 frames @ 60fps
|
||||||
static constexpr float PAUSE_DURATION = 1.667F; // 100 frames @ 60fps
|
static constexpr float PAUSE_DURATION = 1.667F; // 100 frames @ 60fps
|
||||||
static constexpr float REVEAL_PHASE_2_DURATION = 5.333F; // 320 frames (544-224) @ 60fps
|
static constexpr float REVEAL_PHASE_2_DURATION = 5.333F; // 320 frames (544-224) @ 60fps
|
||||||
static constexpr float REVEAL_PHASE_3_DURATION = 2.133F; // 128 frames (672-544) @ 60fps
|
static constexpr float REVEAL_PHASE_3_DURATION = 2.133F; // 128 frames (672-544) @ 60fps
|
||||||
static constexpr float DISPLAY_WITH_SHINE_DURATION = 7.967F; // 478 frames (1150-672) @ 60fps
|
static constexpr float DISPLAY_WITH_SHINE_DURATION = 7.967F; // 478 frames (1150-672) @ 60fps
|
||||||
static constexpr float FADE_OUT_DURATION = 0.833F; // 50 frames (1200-1150) @ 60fps
|
static constexpr float FADE_OUT_DURATION = 0.833F; // 50 frames (1200-1150) @ 60fps
|
||||||
static constexpr float TOTAL_DURATION = 20.0F; // 1200 frames @ 60fps
|
static constexpr float TOTAL_DURATION = 20.0F; // 1200 frames @ 60fps
|
||||||
static constexpr float SHINE_START_TIME = 12.833F; // 770 frames @ 60fps
|
static constexpr float SHINE_START_TIME = 12.833F; // 770 frames @ 60fps
|
||||||
static constexpr float FADE_OUT_START = 19.167F; // 1150 frames @ 60fps
|
static constexpr float FADE_OUT_START = 19.167F; // 1150 frames @ 60fps
|
||||||
static constexpr float PIXELS_PER_SECOND = 15.0F; // Filas reveladas por segundo (REVEAL_SPEED/8*2 = 60/8*2 = 15)
|
static constexpr float PIXELS_PER_SECOND = 15.0F; // Filas reveladas por segundo (REVEAL_SPEED/8*2 = 60/8*2 = 15)
|
||||||
static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps)
|
static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps)
|
||||||
static constexpr int REVEAL_STEPS = 16; // Pasos de revelado por fila (más pasos = efecto más visible)
|
static constexpr int REVEAL_STEPS = 16; // Pasos de revelado por fila (más pasos = efecto más visible)
|
||||||
|
|
||||||
// --- Métodos privados ---
|
// --- Métodos privados ---
|
||||||
void update(); // Actualiza las variables
|
void update(); // Actualiza las variables
|
||||||
void render(); // Dibuja en pantalla
|
void render(); // Dibuja en pantalla
|
||||||
static void handleEvents(); // Comprueba el manejador de eventos
|
static void handleEvents(); // Comprueba el manejador de eventos
|
||||||
static void handleInput(); // Comprueba las entradas
|
static void handleInput(); // Comprueba las entradas
|
||||||
void updateState(float delta_time); // Actualiza la máquina de estados
|
void updateState(float delta_time); // Actualiza la máquina de estados
|
||||||
void transitionToState(State new_state); // Transición entre estados
|
void transitionToState(State new_state); // Transición entre estados
|
||||||
void iniTexts(); // Inicializa los textos
|
void iniTexts(); // Inicializa los textos
|
||||||
void fillTexture(); // Escribe el texto en la textura
|
void fillTexture(); // Escribe el texto en la textura
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Recursos gráficos
|
// Recursos gráficos
|
||||||
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
|
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
|
||||||
std::unique_ptr<PixelReveal> pixel_reveal_; // Efecto de revelado pixel a pixel
|
std::unique_ptr<PixelReveal> pixel_reveal_; // Efecto de revelado pixel a pixel
|
||||||
std::shared_ptr<SurfaceAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
|
std::shared_ptr<SurfaceAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
|
||||||
|
|
||||||
// Temporizadores y estado
|
// Temporizadores y estado
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Temporizador delta para time-based update
|
std::unique_ptr<DeltaTimer> delta_timer_; // Temporizador delta para time-based update
|
||||||
State state_{State::REVEALING_TEXT}; // Estado actual
|
State state_{State::REVEALING_TEXT}; // Estado actual
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
float total_time_{0.0F}; // Tiempo total acumulado
|
float total_time_{0.0F}; // Tiempo total acumulado
|
||||||
float reveal_time_{0.0F}; // Tiempo acumulado solo durante revelación (se congela en pausas)
|
float reveal_time_{0.0F}; // Tiempo acumulado solo durante revelación (se congela en pausas)
|
||||||
|
|
||||||
// Textos
|
// Textos
|
||||||
std::vector<Captions> texts_; // Vector con los textos
|
std::vector<Captions> texts_; // Vector con los textos
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,96 +11,96 @@ class PixelReveal;
|
|||||||
class DeltaTimer;
|
class DeltaTimer;
|
||||||
|
|
||||||
class Ending {
|
class Ending {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Ending();
|
Ending();
|
||||||
~Ending();
|
~Ending();
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Enumeraciones ---
|
// --- Enumeraciones ---
|
||||||
enum class State {
|
enum class State {
|
||||||
WARMING_UP,
|
WARMING_UP,
|
||||||
SCENE_0,
|
SCENE_0,
|
||||||
SCENE_1,
|
SCENE_1,
|
||||||
SCENE_2,
|
SCENE_2,
|
||||||
SCENE_3,
|
SCENE_3,
|
||||||
SCENE_4,
|
SCENE_4,
|
||||||
ENDING
|
ENDING
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
struct EndingSurface {
|
struct EndingSurface {
|
||||||
std::shared_ptr<Surface> image_surface; // Surface a mostrar
|
std::shared_ptr<Surface> image_surface; // Surface a mostrar
|
||||||
std::shared_ptr<SurfaceSprite> image_sprite; // SSprite para mostrar la textura
|
std::shared_ptr<SurfaceSprite> image_sprite; // SSprite para mostrar la textura
|
||||||
std::unique_ptr<PixelReveal> pixel_reveal; // Efecto de revelado pixel a pixel
|
std::unique_ptr<PixelReveal> pixel_reveal; // Efecto de revelado pixel a pixel
|
||||||
int pos_x{0}; // Posición X de renderizado
|
int pos_x{0}; // Posición X de renderizado
|
||||||
int pos_y{0}; // Posición Y de renderizado
|
int pos_y{0}; // Posición Y de renderizado
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextAndPosition {
|
struct TextAndPosition {
|
||||||
std::string caption; // Texto
|
std::string caption; // Texto
|
||||||
int pos{0}; // Posición
|
int pos{0}; // Posición
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextIndex {
|
struct TextIndex {
|
||||||
int index{0}; // Índice del texto
|
int index{0}; // Índice del texto
|
||||||
int trigger{0}; // Disparador temporal
|
int trigger{0}; // Disparador temporal
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceneData {
|
struct SceneData {
|
||||||
std::vector<TextIndex> text_index; // Índices del vector de textos a mostrar y su disparador
|
std::vector<TextIndex> text_index; // Índices del vector de textos a mostrar y su disparador
|
||||||
int picture_index{0}; // Índice del vector de imágenes a mostrar
|
int picture_index{0}; // Índice del vector de imágenes a mostrar
|
||||||
int counter_end{0}; // Valor del contador en el que finaliza la escena
|
int counter_end{0}; // Valor del contador en el que finaliza la escena
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de tiempo (basado en 60 FPS) ---
|
// --- Constantes de tiempo (basado en 60 FPS) ---
|
||||||
static constexpr float WARMUP_DURATION = 3.333F; // 200 frames @ 60fps
|
static constexpr float WARMUP_DURATION = 3.333F; // 200 frames @ 60fps
|
||||||
static constexpr float SCENE_0_DURATION = 16.667F; // 1000 frames @ 60fps
|
static constexpr float SCENE_0_DURATION = 16.667F; // 1000 frames @ 60fps
|
||||||
static constexpr float SCENE_1_DURATION = 23.333F; // 1400 frames @ 60fps
|
static constexpr float SCENE_1_DURATION = 23.333F; // 1400 frames @ 60fps
|
||||||
static constexpr float SCENE_2_DURATION = 16.667F; // 1000 frames @ 60fps
|
static constexpr float SCENE_2_DURATION = 16.667F; // 1000 frames @ 60fps
|
||||||
static constexpr float SCENE_3_DURATION = 13.333F; // 800 frames @ 60fps
|
static constexpr float SCENE_3_DURATION = 13.333F; // 800 frames @ 60fps
|
||||||
static constexpr float SCENE_4_DURATION = 16.667F; // 1000 frames @ 60fps
|
static constexpr float SCENE_4_DURATION = 16.667F; // 1000 frames @ 60fps
|
||||||
static constexpr float TEXT_PIXELS_PER_SECOND = 30.0F; // Filas de texto reveladas por segundo
|
static constexpr float TEXT_PIXELS_PER_SECOND = 30.0F; // Filas de texto reveladas por segundo
|
||||||
static constexpr float IMAGE_PIXELS_PER_SECOND = 60.0F; // Filas de imagen reveladas por segundo
|
static constexpr float IMAGE_PIXELS_PER_SECOND = 60.0F; // Filas de imagen reveladas por segundo
|
||||||
static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps)
|
static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps)
|
||||||
static constexpr int REVEAL_STEPS = 4; // Pasos de revelado por fila
|
static constexpr int REVEAL_STEPS = 4; // Pasos de revelado por fila
|
||||||
static constexpr float TEXT_LAPSE = 1.333F; // 80 frames @ 60fps
|
static constexpr float TEXT_LAPSE = 1.333F; // 80 frames @ 60fps
|
||||||
static constexpr float FADEOUT_START_OFFSET = 1.667F; // Inicio cortinilla 100 frames antes del fin
|
static constexpr float FADEOUT_START_OFFSET = 1.667F; // Inicio cortinilla 100 frames antes del fin
|
||||||
static constexpr float COVER_PIXELS_PER_SECOND = 120.0F; // Filas cubiertas por segundo
|
static constexpr float COVER_PIXELS_PER_SECOND = 120.0F; // Filas cubiertas por segundo
|
||||||
static constexpr int COVER_STEPS = 4; // Pasos por fila
|
static constexpr int COVER_STEPS = 4; // Pasos por fila
|
||||||
static constexpr float ENDING_DURATION = 2.0F; // Duración del estado ENDING (2 segundos)
|
static constexpr float ENDING_DURATION = 2.0F; // Duración del estado ENDING (2 segundos)
|
||||||
static constexpr int MUSIC_FADE_DURATION = 1800; // Fade de audio en milisegundos (1.8 segundos)
|
static constexpr int MUSIC_FADE_DURATION = 1800; // Fade de audio en milisegundos (1.8 segundos)
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza el objeto
|
void update(); // Actualiza el objeto
|
||||||
void render(); // Dibuja el final en pantalla
|
void render(); // Dibuja el final en pantalla
|
||||||
static void handleEvents(); // Comprueba el manejador de eventos
|
static void handleEvents(); // Comprueba el manejador de eventos
|
||||||
static void handleInput(); // Comprueba las entradas
|
static void handleInput(); // Comprueba las entradas
|
||||||
void iniTexts(); // Inicializa los textos
|
void iniTexts(); // Inicializa los textos
|
||||||
void iniPics(); // Inicializa las imágenes
|
void iniPics(); // Inicializa las imágenes
|
||||||
void iniScenes(); // Inicializa las escenas
|
void iniScenes(); // Inicializa las escenas
|
||||||
void updateState(float delta_time); // Actualiza la máquina de estados
|
void updateState(float delta_time); // Actualiza la máquina de estados
|
||||||
void handleSceneFadeout(float scene_duration, float delta_time); // Lógica de fade común a los estados SCENE_N
|
void handleSceneFadeout(float scene_duration, float delta_time); // Lógica de fade común a los estados SCENE_N
|
||||||
void transitionToState(State new_state); // Transición entre estados
|
void transitionToState(State new_state); // Transición entre estados
|
||||||
void updateSpriteCovers(); // Actualiza las cortinillas de los elementos
|
void updateSpriteCovers(); // Actualiza las cortinillas de los elementos
|
||||||
void checkChangeScene(); // Comprueba si se ha de cambiar de escena
|
void checkChangeScene(); // Comprueba si se ha de cambiar de escena
|
||||||
void updateMusicVolume() const; // Actualiza el volumen de la música
|
void updateMusicVolume() const; // Actualiza el volumen de la música
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros a recursos
|
// Objetos y punteros a recursos
|
||||||
std::unique_ptr<PixelReveal> scene_cover_; // Cortinilla de salida (negro sobre la escena)
|
std::unique_ptr<PixelReveal> scene_cover_; // Cortinilla de salida (negro sobre la escena)
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update
|
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update
|
||||||
std::vector<EndingSurface> sprite_texts_; // Vector con los sprites de texto con su cortinilla
|
std::vector<EndingSurface> sprite_texts_; // Vector con los sprites de texto con su cortinilla
|
||||||
std::vector<EndingSurface> sprite_pics_; // Vector con los sprites de imágenes con su cortinilla
|
std::vector<EndingSurface> sprite_pics_; // Vector con los sprites de imágenes con su cortinilla
|
||||||
std::vector<SceneData> scenes_; // Vector con los textos e imágenes de cada escena
|
std::vector<SceneData> scenes_; // Vector con los textos e imágenes de cada escena
|
||||||
|
|
||||||
// Variables de estado
|
// Variables de estado
|
||||||
State state_{State::WARMING_UP}; // Estado actual
|
State state_{State::WARMING_UP}; // Estado actual
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
float total_time_{0.0F}; // Tiempo total acumulado desde el inicio
|
float total_time_{0.0F}; // Tiempo total acumulado desde el inicio
|
||||||
float fadeout_time_{0.0F}; // Tiempo acumulado para la cortinilla de salida
|
float fadeout_time_{0.0F}; // Tiempo acumulado para la cortinilla de salida
|
||||||
int current_scene_{0}; // Escena actual (0-4)
|
int current_scene_{0}; // Escena actual (0-4)
|
||||||
};
|
};
|
||||||
@@ -13,82 +13,82 @@ class SurfaceMovingSprite;
|
|||||||
class DeltaTimer;
|
class DeltaTimer;
|
||||||
|
|
||||||
class Ending2 {
|
class Ending2 {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Ending2();
|
Ending2();
|
||||||
~Ending2() = default;
|
~Ending2() = default;
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Enumeraciones ---
|
// --- Enumeraciones ---
|
||||||
enum class EndingState : int {
|
enum class EndingState : int {
|
||||||
PRE_CREDITS, // Estado previo a los créditos
|
PRE_CREDITS, // Estado previo a los créditos
|
||||||
CREDITS, // Estado de los créditos
|
CREDITS, // Estado de los créditos
|
||||||
POST_CREDITS, // Estado posterior a los créditos
|
POST_CREDITS, // Estado posterior a los créditos
|
||||||
FADING, // Estado de fundido de los textos a negro
|
FADING, // Estado de fundido de los textos a negro
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
struct State {
|
struct State {
|
||||||
EndingState state{EndingState::PRE_CREDITS}; // Estado actual
|
EndingState state{EndingState::PRE_CREDITS}; // Estado actual
|
||||||
float duration{0.0F}; // Duración en segundos para el estado actual
|
float duration{0.0F}; // Duración en segundos para el estado actual
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr int FIRST_COL = GameCanvas::FIRST_QUARTER_X + (GameCanvas::WIDTH / 16); // Primera columna por donde desfilan los sprites
|
static constexpr int FIRST_COL = GameCanvas::FIRST_QUARTER_X + (GameCanvas::WIDTH / 16); // Primera columna por donde desfilan los sprites
|
||||||
static constexpr int SECOND_COL = GameCanvas::THIRD_QUARTER_X - (GameCanvas::WIDTH / 16); // Segunda columna por donde desfilan los sprites
|
static constexpr int SECOND_COL = GameCanvas::THIRD_QUARTER_X - (GameCanvas::WIDTH / 16); // Segunda columna por donde desfilan los sprites
|
||||||
static constexpr int DIST_SPRITE_TEXT = 8; // Distancia entre el sprite y el texto que lo acompaña
|
static constexpr int DIST_SPRITE_TEXT = 8; // Distancia entre el sprite y el texto que lo acompaña
|
||||||
static constexpr int DIST_SPRITE_SPRITE = 0; // Distancia entre dos sprites de la misma columna
|
static constexpr int DIST_SPRITE_SPRITE = 0; // Distancia entre dos sprites de la misma columna
|
||||||
static constexpr int INITIAL_Y_OFFSET = 40; // Offset inicial en Y para posicionar sprites
|
static constexpr int INITIAL_Y_OFFSET = 40; // Offset inicial en Y para posicionar sprites
|
||||||
static constexpr int SCREEN_MESH_HEIGHT = 8; // Altura de la malla superior/inferior de la pantalla
|
static constexpr int SCREEN_MESH_HEIGHT = 8; // Altura de la malla superior/inferior de la pantalla
|
||||||
static constexpr int FADE_H = 24; // Alçada de la zona de dissolució als cantons (files)
|
static constexpr int FADE_H = 24; // Alçada de la zona de dissolució als cantons (files)
|
||||||
static constexpr float TRANSITION_DURATION_MS = 500.0F; // ms per canviar d'estat (generar o dissoldre)
|
static constexpr float TRANSITION_DURATION_MS = 500.0F; // ms per canviar d'estat (generar o dissoldre)
|
||||||
static constexpr int ENTRY_EXIT_PADDING = 2; // px de padding als bordes per activar dissolució/generació
|
static constexpr int ENTRY_EXIT_PADDING = 2; // px de padding als bordes per activar dissolució/generació
|
||||||
static constexpr int TEXT_SPACING_MULTIPLIER = 2; // Multiplicador para espaciado entre líneas de texto
|
static constexpr int TEXT_SPACING_MULTIPLIER = 2; // Multiplicador para espaciado entre líneas de texto
|
||||||
|
|
||||||
// Constantes de tiempo (basadas en tiempo real, no en frames)
|
// Constantes de tiempo (basadas en tiempo real, no en frames)
|
||||||
static constexpr float SPRITE_DESP_SPEED = -12.0F; // Velocidad de desplazamiento en pixels/segundo (era -0.2 px/frame @ 60fps)
|
static constexpr float SPRITE_DESP_SPEED = -12.0F; // Velocidad de desplazamiento en pixels/segundo (era -0.2 px/frame @ 60fps)
|
||||||
static constexpr float STATE_PRE_CREDITS_DURATION = 3.0F; // Duración del estado previo a créditos en segundos
|
static constexpr float STATE_PRE_CREDITS_DURATION = 3.0F; // Duración del estado previo a créditos en segundos
|
||||||
static constexpr float STATE_POST_CREDITS_DURATION = 5.0F; // Duración del estado posterior a créditos en segundos
|
static constexpr float STATE_POST_CREDITS_DURATION = 5.0F; // Duración del estado posterior a créditos en segundos
|
||||||
static constexpr float STATE_FADE_DURATION = 5.0F; // Duración del fade final en segundos
|
static constexpr float STATE_FADE_DURATION = 5.0F; // Duración del fade final en segundos
|
||||||
static constexpr int MUSIC_FADE_DURATION = 3000; // Duración del fade de música en milisegundos (para Audio API)
|
static constexpr int MUSIC_FADE_DURATION = 3000; // Duración del fade de música en milisegundos (para Audio API)
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza el objeto
|
void update(); // Actualiza el objeto
|
||||||
void render(); // Dibuja el final en pantalla
|
void render(); // Dibuja el final en pantalla
|
||||||
static void handleEvents(); // Comprueba el manejador de eventos
|
static void handleEvents(); // Comprueba el manejador de eventos
|
||||||
static void handleInput(); // Comprueba las entradas
|
static void handleInput(); // Comprueba las entradas
|
||||||
void updateState(float delta_time); // Actualiza el estado
|
void updateState(float delta_time); // Actualiza el estado
|
||||||
void transitionToState(EndingState new_state); // Transición entre estados
|
void transitionToState(EndingState new_state); // Transición entre estados
|
||||||
void iniSpriteList(); // Inicializa la lista de sprites
|
void iniSpriteList(); // Inicializa la lista de sprites
|
||||||
void loadSprites(); // Carga todos los sprites desde una lista
|
void loadSprites(); // Carga todos los sprites desde una lista
|
||||||
void updateSprites(float delta); // Actualiza los sprites
|
void updateSprites(float delta); // Actualiza los sprites
|
||||||
void updateTextSprites(float delta); // Actualiza los sprites de texto
|
void updateTextSprites(float delta); // Actualiza los sprites de texto
|
||||||
void updateTexts(float delta); // Actualiza los sprites de texto del final
|
void updateTexts(float delta); // Actualiza los sprites de texto del final
|
||||||
void renderSprites(); // Dibuja los sprites
|
void renderSprites(); // Dibuja los sprites
|
||||||
void renderSpriteTexts(); // Dibuja los sprites con el texto
|
void renderSpriteTexts(); // Dibuja los sprites con el texto
|
||||||
void renderTexts(); // Dibuja los sprites con el texto del final
|
void renderTexts(); // Dibuja los sprites con el texto del final
|
||||||
void placeSprites(); // Coloca los sprites en su sitio
|
void placeSprites(); // Coloca los sprites en su sitio
|
||||||
void createSpriteTexts(); // Crea los sprites con las texturas con los textos
|
void createSpriteTexts(); // Crea los sprites con las texturas con los textos
|
||||||
void createTexts(); // Crea los sprites con las texturas con los textos del final
|
void createTexts(); // Crea los sprites con las texturas con los textos del final
|
||||||
void updateFinalFade(); // Actualiza el fade final
|
void updateFinalFade(); // Actualiza el fade final
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros a recursos
|
// Objetos y punteros a recursos
|
||||||
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprites_; // Vector con todos los sprites a dibujar
|
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprites_; // Vector con todos los sprites a dibujar
|
||||||
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
|
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
|
||||||
std::vector<std::shared_ptr<SurfaceDissolveSprite>> texts_; // Vector con los sprites de texto
|
std::vector<std::shared_ptr<SurfaceDissolveSprite>> texts_; // Vector con los sprites de texto
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update
|
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update
|
||||||
|
|
||||||
// Variables de estado
|
// Variables de estado
|
||||||
State state_; // Controla el estado de la clase
|
State state_; // Controla el estado de la clase
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
|
|
||||||
// Variables auxiliares
|
// Variables auxiliares
|
||||||
std::vector<std::string> sprite_list_; // Lista con todos los sprites a dibujar
|
std::vector<std::string> sprite_list_; // Lista con todos los sprites a dibujar
|
||||||
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
||||||
float sprite_max_width_{0.0F}; // El valor de ancho del sprite más ancho
|
float sprite_max_width_{0.0F}; // El valor de ancho del sprite más ancho
|
||||||
float sprite_max_height_{0.0F}; // El valor de alto del sprite más alto
|
float sprite_max_height_{0.0F}; // El valor de alto del sprite más alto
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,120 +16,120 @@ class Stats; // lines 15-15
|
|||||||
class Surface;
|
class Surface;
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
public:
|
public:
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
DEMO,
|
DEMO,
|
||||||
GAME
|
GAME
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
PLAYING, // Normal gameplay
|
PLAYING, // Normal gameplay
|
||||||
BLACK_SCREEN, // Black screen after death (0.30s)
|
BLACK_SCREEN, // Black screen after death (0.30s)
|
||||||
GAME_OVER, // Intermediate state before changing scene
|
GAME_OVER, // Intermediate state before changing scene
|
||||||
FADE_TO_ENDING, // Fade out transition
|
FADE_TO_ENDING, // Fade out transition
|
||||||
POST_FADE_ENDING, // Black screen delay before ending
|
POST_FADE_ENDING, // Black screen delay before ending
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
explicit Game(Mode mode);
|
explicit Game(Mode mode);
|
||||||
~Game();
|
~Game();
|
||||||
|
|
||||||
// --- Bucle para el juego ---
|
// --- Bucle para el juego ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Constantes de tiempo ---
|
// --- Constantes de tiempo ---
|
||||||
static constexpr float BLACK_SCREEN_DURATION = 0.30F; // Duración de la pantalla negra en segundos (20 frames a 66.67fps)
|
static constexpr float BLACK_SCREEN_DURATION = 0.30F; // Duración de la pantalla negra en segundos (20 frames a 66.67fps)
|
||||||
static constexpr float GAME_OVER_THRESHOLD = 0.255F; // Tiempo antes del game over en segundos (17 frames a 66.67fps)
|
static constexpr float GAME_OVER_THRESHOLD = 0.255F; // Tiempo antes del game over en segundos (17 frames a 66.67fps)
|
||||||
static constexpr float DEMO_ROOM_DURATION = 6.0F; // Duración de cada habitación en modo demo en segundos (400 frames)
|
static constexpr float DEMO_ROOM_DURATION = 6.0F; // Duración de cada habitación en modo demo en segundos (400 frames)
|
||||||
static constexpr float JAIL_RESTORE_INTERVAL = 1.5F; // Intervalo de restauración de vidas en la Jail en segundos (100 frames)
|
static constexpr float JAIL_RESTORE_INTERVAL = 1.5F; // Intervalo de restauración de vidas en la Jail en segundos (100 frames)
|
||||||
static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade en segundos
|
static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade en segundos
|
||||||
static constexpr float POST_FADE_DELAY = 2.0F; // Duración de la pantalla negra después del fade
|
static constexpr float POST_FADE_DELAY = 2.0F; // Duración de la pantalla negra después del fade
|
||||||
|
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
struct DemoData {
|
struct DemoData {
|
||||||
float time_accumulator{0.0F}; // Acumulador de tiempo para el modo demo
|
float time_accumulator{0.0F}; // Acumulador de tiempo para el modo demo
|
||||||
int room_index{0}; // Índice para el vector de habitaciones
|
int room_index{0}; // Índice para el vector de habitaciones
|
||||||
std::vector<std::string> rooms; // Listado con los mapas de la demo
|
std::vector<std::string> rooms; // Listado con los mapas de la demo
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza el juego, las variables, comprueba la entrada, etc.
|
void update(); // Actualiza el juego, las variables, comprueba la entrada, etc.
|
||||||
void render(); // Pinta los objetos en pantalla
|
void render(); // Pinta los objetos en pantalla
|
||||||
void handleEvents(); // Comprueba los eventos de la cola
|
void handleEvents(); // Comprueba los eventos de la cola
|
||||||
void renderRoomName(); // Escribe el nombre de la pantalla
|
void renderRoomName(); // Escribe el nombre de la pantalla
|
||||||
void transitionToState(State new_state); // Cambia al estado especificado y resetea los timers
|
void transitionToState(State new_state); // Cambia al estado especificado y resetea los timers
|
||||||
void updatePlaying(float delta_time); // Actualiza el juego en estado PLAYING
|
void updatePlaying(float delta_time); // Actualiza el juego en estado PLAYING
|
||||||
void updateBlackScreen(float delta_time); // Actualiza el juego en estado BLACK_SCREEN
|
void updateBlackScreen(float delta_time); // Actualiza el juego en estado BLACK_SCREEN
|
||||||
void updateGameOver(float delta_time); // Actualiza el juego en estado GAME_OVER
|
void updateGameOver(float delta_time); // Actualiza el juego en estado GAME_OVER
|
||||||
void updateFadeToEnding(float delta_time); // Actualiza el juego en estado FADE_TO_ENDING
|
void updateFadeToEnding(float delta_time); // Actualiza el juego en estado FADE_TO_ENDING
|
||||||
void updatePostFadeEnding(float delta_time); // Actualiza el juego en estado POST_FADE_ENDING
|
void updatePostFadeEnding(float delta_time); // Actualiza el juego en estado POST_FADE_ENDING
|
||||||
void renderPlaying(); // Renderiza el juego en estado PLAYING (directo a pantalla)
|
void renderPlaying(); // Renderiza el juego en estado PLAYING (directo a pantalla)
|
||||||
static void renderBlackScreen(); // Renderiza el juego en estado BLACK_SCREEN (pantalla negra)
|
static void renderBlackScreen(); // Renderiza el juego en estado BLACK_SCREEN (pantalla negra)
|
||||||
static void renderGameOver(); // Renderiza el juego en estado GAME_OVER (pantalla negra)
|
static void renderGameOver(); // Renderiza el juego en estado GAME_OVER (pantalla negra)
|
||||||
void renderFadeToEnding(); // Renderiza el juego en estado FADE_TO_ENDING (via backbuffer)
|
void renderFadeToEnding(); // Renderiza el juego en estado FADE_TO_ENDING (via backbuffer)
|
||||||
static void renderPostFadeEnding(); // Renderiza el juego en estado POST_FADE_ENDING (pantalla negra)
|
static void renderPostFadeEnding(); // Renderiza el juego en estado POST_FADE_ENDING (pantalla negra)
|
||||||
auto changeRoom(const std::string& room_path) -> bool; // Cambia de habitación
|
auto changeRoom(const std::string& room_path) -> bool; // Cambia de habitación
|
||||||
void handleInput(); // Comprueba el teclado
|
void handleInput(); // Comprueba el teclado
|
||||||
void checkPlayerIsOnBorder(); // Comprueba si el jugador esta en el borde de la pantalla y actua
|
void checkPlayerIsOnBorder(); // Comprueba si el jugador esta en el borde de la pantalla y actua
|
||||||
auto checkPlayerAndEnemies() -> bool; // Comprueba las colisiones del jugador con los enemigos
|
auto checkPlayerAndEnemies() -> bool; // Comprueba las colisiones del jugador con los enemigos
|
||||||
void checkPlayerAndItems(); // Comprueba las colisiones del jugador con los objetos
|
void checkPlayerAndItems(); // Comprueba las colisiones del jugador con los objetos
|
||||||
void checkIfPlayerIsAlive(); // Comprueba si el jugador esta vivo
|
void checkIfPlayerIsAlive(); // Comprueba si el jugador esta vivo
|
||||||
void killPlayer(); // Mata al jugador
|
void killPlayer(); // Mata al jugador
|
||||||
void setScoreBoardColor(); // Pone el color del marcador en función del color del borde de la habitación
|
void setScoreBoardColor(); // Pone el color del marcador en función del color del borde de la habitación
|
||||||
auto checkEndGame() -> bool; // Comprueba si ha finalizado el juego
|
auto checkEndGame() -> bool; // Comprueba si ha finalizado el juego
|
||||||
static auto getTotalItems() -> int; // Obtiene la cantidad total de items que hay en el mapeado del juego
|
static auto getTotalItems() -> int; // Obtiene la cantidad total de items que hay en el mapeado del juego
|
||||||
void togglePause(); // Pone el juego en pausa
|
void togglePause(); // Pone el juego en pausa
|
||||||
void checkRestoringJail(float delta_time); // Da vidas al jugador cuando está en la Jail
|
void checkRestoringJail(float delta_time); // Da vidas al jugador cuando está en la Jail
|
||||||
void initStats(); // Inicializa el diccionario de las estadísticas
|
void initStats(); // Inicializa el diccionario de las estadísticas
|
||||||
void fillRoomNameTexture(); // Pone el nombre de la habitación en la textura
|
void fillRoomNameTexture(); // Pone el nombre de la habitación en la textura
|
||||||
void checkSomeCheevos(); // Comprueba algunos logros
|
void checkSomeCheevos(); // Comprueba algunos logros
|
||||||
void checkEndGameCheevos(); // Comprueba los logros de completar el juego
|
void checkEndGameCheevos(); // Comprueba los logros de completar el juego
|
||||||
void initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room); // Inicializa al jugador
|
void initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room); // Inicializa al jugador
|
||||||
void createRoomNameTexture(); // Crea la textura para poner el nombre de la habitación
|
void createRoomNameTexture(); // Crea la textura para poner el nombre de la habitación
|
||||||
void keepMusicPlaying(); // Hace sonar la música
|
void keepMusicPlaying(); // Hace sonar la música
|
||||||
void demoInit(); // DEMO MODE: Inicializa las variables para el modo demo
|
void demoInit(); // DEMO MODE: Inicializa las variables para el modo demo
|
||||||
void demoCheckRoomChange(float delta_time); // DEMO MODE: Comprueba si se ha de cambiar de habitación
|
void demoCheckRoomChange(float delta_time); // DEMO MODE: Comprueba si se ha de cambiar de habitación
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void updateDebugInfo(); // Pone la información de debug en pantalla
|
void updateDebugInfo(); // Pone la información de debug en pantalla
|
||||||
static void renderDebugInfo(); // Pone la información de debug en pantalla
|
static void renderDebugInfo(); // Pone la información de debug en pantalla
|
||||||
void handleDebugEvents(const SDL_Event& event); // Comprueba los eventos
|
void handleDebugEvents(const SDL_Event& event); // Comprueba los eventos
|
||||||
void handleDebugMouseDrag(float delta_time); // Maneja el arrastre del jugador con el ratón (debug)
|
void handleDebugMouseDrag(float delta_time); // Maneja el arrastre del jugador con el ratón (debug)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros a recursos
|
// Objetos y punteros a recursos
|
||||||
std::shared_ptr<Scoreboard::Data> scoreboard_data_; // Estructura con los datos del marcador
|
std::shared_ptr<Scoreboard::Data> scoreboard_data_; // Estructura con los datos del marcador
|
||||||
std::shared_ptr<Scoreboard> scoreboard_; // Objeto encargado de gestionar el marcador
|
std::shared_ptr<Scoreboard> scoreboard_; // Objeto encargado de gestionar el marcador
|
||||||
std::shared_ptr<RoomTracker> room_tracker_; // Lleva el control de las habitaciones visitadas
|
std::shared_ptr<RoomTracker> room_tracker_; // Lleva el control de las habitaciones visitadas
|
||||||
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
||||||
std::shared_ptr<Player> player_; // Objeto con el jugador
|
std::shared_ptr<Player> player_; // Objeto con el jugador
|
||||||
std::shared_ptr<Stats> stats_; // Objeto encargado de gestionar las estadísticas
|
std::shared_ptr<Stats> stats_; // Objeto encargado de gestionar las estadísticas
|
||||||
std::shared_ptr<Surface> room_name_surface_; // Textura para escribir el nombre de la habitación
|
std::shared_ptr<Surface> room_name_surface_; // Textura para escribir el nombre de la habitación
|
||||||
std::shared_ptr<Surface> game_backbuffer_surface_; // Backbuffer para efectos de fade
|
std::shared_ptr<Surface> game_backbuffer_surface_; // Backbuffer para efectos de fade
|
||||||
|
|
||||||
// Variables de estado del juego
|
// Variables de estado del juego
|
||||||
Mode mode_; // Modo del juego
|
Mode mode_; // Modo del juego
|
||||||
State state_{State::PLAYING}; // Estado actual de la escena
|
State state_{State::PLAYING}; // Estado actual de la escena
|
||||||
DeltaTimer delta_timer_; // Timer para calcular delta time
|
DeltaTimer delta_timer_; // Timer para calcular delta time
|
||||||
std::string current_room_; // Fichero de la habitación actual
|
std::string current_room_; // Fichero de la habitación actual
|
||||||
Player::SpawnData spawn_data_; // Lugar de la habitación donde aparece el jugador
|
Player::SpawnData spawn_data_; // Lugar de la habitación donde aparece el jugador
|
||||||
int total_items_; // Cantidad total de items que hay en el mapeado del juego
|
int total_items_; // Cantidad total de items que hay en el mapeado del juego
|
||||||
bool paused_{false}; // Indica si el juego se encuentra en pausa
|
bool paused_{false}; // Indica si el juego se encuentra en pausa
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
float fade_accumulator_{0.0F}; // Acumulador de tiempo para el fade
|
float fade_accumulator_{0.0F}; // Acumulador de tiempo para el fade
|
||||||
|
|
||||||
// Variables de demo mode
|
// Variables de demo mode
|
||||||
DemoData demo_; // Variables para el modo demo
|
DemoData demo_; // Variables para el modo demo
|
||||||
|
|
||||||
// Variables de efectos visuales
|
// Variables de efectos visuales
|
||||||
SDL_FRect room_name_rect_; // Rectangulo donde pintar la textura con el nombre de la habitación
|
SDL_FRect room_name_rect_; // Rectangulo donde pintar la textura con el nombre de la habitación
|
||||||
float jail_restore_time_{0.0F}; // Tiempo acumulado para restauración de vidas en la Jail
|
float jail_restore_time_{0.0F}; // Tiempo acumulado para restauración de vidas en la Jail
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// Variables de debug para arrastre con ratón
|
// Variables de debug para arrastre con ratón
|
||||||
bool debug_dragging_player_{false}; // Indica si estamos arrastrando al jugador con el ratón
|
bool debug_dragging_player_{false}; // Indica si estamos arrastrando al jugador con el ratón
|
||||||
float debug_drag_speed_{0.0F}; // Velocidad actual del arrastre (ease-in)
|
float debug_drag_speed_{0.0F}; // Velocidad actual del arrastre (ease-in)
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -8,62 +8,62 @@ class SurfaceAnimatedSprite; // lines 7-7
|
|||||||
class DeltaTimer; // Forward declaration
|
class DeltaTimer; // Forward declaration
|
||||||
|
|
||||||
class GameOver {
|
class GameOver {
|
||||||
public:
|
public:
|
||||||
// Constructor y Destructor
|
// Constructor y Destructor
|
||||||
GameOver();
|
GameOver();
|
||||||
~GameOver() = default;
|
~GameOver() = default;
|
||||||
|
|
||||||
// Bucle principal
|
// Bucle principal
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Enumeraciones ---
|
// --- Enumeraciones ---
|
||||||
enum class State {
|
enum class State {
|
||||||
WAITING, // Espera inicial antes de empezar
|
WAITING, // Espera inicial antes de empezar
|
||||||
FADE_IN, // Fade in de colores desde black
|
FADE_IN, // Fade in de colores desde black
|
||||||
DISPLAY, // Mostrando contenido con color brillante
|
DISPLAY, // Mostrando contenido con color brillante
|
||||||
FADE_OUT, // Fade out hacia black
|
FADE_OUT, // Fade out hacia black
|
||||||
ENDING, // Pantalla en negro antes de salir
|
ENDING, // Pantalla en negro antes de salir
|
||||||
TRANSITION // Cambio a logo
|
TRANSITION // Cambio a logo
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de duración (segundos) ---
|
// --- Constantes de duración (segundos) ---
|
||||||
static constexpr float WAITING_DURATION = 0.8F; // Espera inicial
|
static constexpr float WAITING_DURATION = 0.8F; // Espera inicial
|
||||||
static constexpr float FADE_IN_DURATION = 0.32F; // Duración del fade in
|
static constexpr float FADE_IN_DURATION = 0.32F; // Duración del fade in
|
||||||
static constexpr float DISPLAY_DURATION = 4.64F; // Duración mostrando contenido
|
static constexpr float DISPLAY_DURATION = 4.64F; // Duración mostrando contenido
|
||||||
static constexpr float FADE_OUT_DURATION = 0.32F; // Duración del fade out
|
static constexpr float FADE_OUT_DURATION = 0.32F; // Duración del fade out
|
||||||
static constexpr float ENDING_DURATION = 1.12F; // Espera en negro antes de salir
|
static constexpr float ENDING_DURATION = 1.12F; // Espera en negro antes de salir
|
||||||
|
|
||||||
// --- Constantes de posición ---
|
// --- Constantes de posición ---
|
||||||
static constexpr int TEXT_Y = 32; // Posición Y del texto principal
|
static constexpr int TEXT_Y = 32; // Posición Y del texto principal
|
||||||
static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y
|
static constexpr int SPRITE_Y_OFFSET = 30; // Offset Y para sprites desde TEXT_Y
|
||||||
static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro
|
static constexpr int PLAYER_X_OFFSET = 10; // Offset X del jugador desde el centro
|
||||||
static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro
|
static constexpr int TV_X_OFFSET = 10; // Offset X del TV desde el centro
|
||||||
static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y
|
static constexpr int ITEMS_Y_OFFSET = 80; // Offset Y del texto de items desde TEXT_Y
|
||||||
static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y
|
static constexpr int ROOMS_Y_OFFSET = 90; // Offset Y del texto de rooms desde TEXT_Y
|
||||||
static constexpr int NIGHTMARE_TITLE_Y_OFFSET = 110; // Offset Y del título nightmare desde TEXT_Y
|
static constexpr int NIGHTMARE_TITLE_Y_OFFSET = 110; // Offset Y del título nightmare desde TEXT_Y
|
||||||
static constexpr int NIGHTMARE_TEXT_Y_OFFSET = 120; // Offset Y del texto nightmare desde TEXT_Y
|
static constexpr int NIGHTMARE_TEXT_Y_OFFSET = 120; // Offset Y del texto nightmare desde TEXT_Y
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza el objeto
|
void update(); // Actualiza el objeto
|
||||||
void render(); // Dibuja el final en pantalla
|
void render(); // Dibuja el final en pantalla
|
||||||
static void handleEvents(); // Comprueba el manejador de eventos
|
static void handleEvents(); // Comprueba el manejador de eventos
|
||||||
static void handleInput(); // Comprueba las entradas
|
static void handleInput(); // Comprueba las entradas
|
||||||
void updateState(); // Actualiza el estado y transiciones
|
void updateState(); // Actualiza el estado y transiciones
|
||||||
void updateColor(); // Actualiza el color usado para renderizar
|
void updateColor(); // Actualiza el color usado para renderizar
|
||||||
void renderSprites(); // Dibuja los sprites
|
void renderSprites(); // Dibuja los sprites
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros a recursos
|
// Objetos y punteros a recursos
|
||||||
std::shared_ptr<SurfaceAnimatedSprite> player_sprite_; // Sprite con el jugador
|
std::shared_ptr<SurfaceAnimatedSprite> player_sprite_; // Sprite con el jugador
|
||||||
std::shared_ptr<SurfaceAnimatedSprite> tv_sprite_; // Sprite con el televisor
|
std::shared_ptr<SurfaceAnimatedSprite> tv_sprite_; // Sprite con el televisor
|
||||||
std::shared_ptr<DeltaTimer> delta_timer_; // Timer para time-based logic
|
std::shared_ptr<DeltaTimer> delta_timer_; // Timer para time-based logic
|
||||||
|
|
||||||
// Variables de estado de la escena
|
// Variables de estado de la escena
|
||||||
State state_{State::WAITING}; // Estado actual de la escena
|
State state_{State::WAITING}; // Estado actual de la escena
|
||||||
float elapsed_time_{0.0F}; // Tiempo transcurrido en el estado actual
|
float elapsed_time_{0.0F}; // Tiempo transcurrido en el estado actual
|
||||||
|
|
||||||
// Variables de efectos visuales
|
// Variables de efectos visuales
|
||||||
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
||||||
Uint8 color_{0}; // Color actual para texto y sprites
|
Uint8 color_{0}; // Color actual para texto y sprites
|
||||||
};
|
};
|
||||||
@@ -11,113 +11,113 @@ class SurfaceSprite; // Forward declaration
|
|||||||
class Surface; // Forward declaration
|
class Surface; // Forward declaration
|
||||||
|
|
||||||
class LoadingScreen {
|
class LoadingScreen {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
LoadingScreen();
|
LoadingScreen();
|
||||||
~LoadingScreen();
|
~LoadingScreen();
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Enumeraciones ---
|
// --- Enumeraciones ---
|
||||||
// Estados de la secuencia de carga
|
// Estados de la secuencia de carga
|
||||||
enum class State {
|
enum class State {
|
||||||
SILENT1, // Pausa inicial antes de empezar
|
SILENT1, // Pausa inicial antes de empezar
|
||||||
HEADER1, // Cabecera
|
HEADER1, // Cabecera
|
||||||
DATA1, // Datos
|
DATA1, // Datos
|
||||||
SILENT2, // Segunda pausa
|
SILENT2, // Segunda pausa
|
||||||
HEADER2, // Cabecera pantalla
|
HEADER2, // Cabecera pantalla
|
||||||
LOADING_MONO, // Carga de pantalla monocromática (escaneo de líneas)
|
LOADING_MONO, // Carga de pantalla monocromática (escaneo de líneas)
|
||||||
LOADING_COLOR, // Carga de pantalla en color (bloques)
|
LOADING_COLOR, // Carga de pantalla en color (bloques)
|
||||||
DATA2, // Datos
|
DATA2, // Datos
|
||||||
COMPLETE // Carga completa
|
COMPLETE // Carga completa
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tipos de borde para la pantalla de carga
|
// Tipos de borde para la pantalla de carga
|
||||||
enum class Border {
|
enum class Border {
|
||||||
NONE,
|
NONE,
|
||||||
YELLOW_AND_BLUE,
|
YELLOW_AND_BLUE,
|
||||||
RED_AND_CYAN,
|
RED_AND_CYAN,
|
||||||
WHITE,
|
WHITE,
|
||||||
BLACK,
|
BLACK,
|
||||||
RED,
|
RED,
|
||||||
CYAN
|
CYAN
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
struct Carrier {
|
struct Carrier {
|
||||||
float offset{0.0F}; // Offset para la carga de cabeceras
|
float offset{0.0F}; // Offset para la carga de cabeceras
|
||||||
bool toggle{false}; // Para cambiar el color inicial
|
bool toggle{false}; // Para cambiar el color inicial
|
||||||
float total_time{0.0F}; // Tiempo acumulado para modulación de velocidad
|
float total_time{0.0F}; // Tiempo acumulado para modulación de velocidad
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Noise {
|
struct Noise {
|
||||||
float value{0.0F}; // Nivel actual de ruido (0.0 a 1.0)
|
float value{0.0F}; // Nivel actual de ruido (0.0 a 1.0)
|
||||||
float total_time{0.0F}; // Tiempo acumulado para modulación
|
float total_time{0.0F}; // Tiempo acumulado para modulación
|
||||||
bool crossed{false}; // Flag para detectar cruce de umbral
|
bool crossed{false}; // Flag para detectar cruce de umbral
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de tiempo (en segundos) ---
|
// --- Constantes de tiempo (en segundos) ---
|
||||||
static constexpr float SILENT1_DURATION = 2.0F; // Pausa inicial
|
static constexpr float SILENT1_DURATION = 2.0F; // Pausa inicial
|
||||||
static constexpr float HEADER1_DURATION = 4.0F; // Cabecera
|
static constexpr float HEADER1_DURATION = 4.0F; // Cabecera
|
||||||
static constexpr float DATA1_DURATION = 0.18F; // Datos
|
static constexpr float DATA1_DURATION = 0.18F; // Datos
|
||||||
static constexpr float SILENT2_DURATION = 1.6F; // Segunda pausa
|
static constexpr float SILENT2_DURATION = 1.6F; // Segunda pausa
|
||||||
static constexpr float HEADER2_DURATION = 2.0F; // Cabecera pantalla
|
static constexpr float HEADER2_DURATION = 2.0F; // Cabecera pantalla
|
||||||
static constexpr float LOADING_MONO_DURATION = 16.0F; // Duración total de la carga monocromática
|
static constexpr float LOADING_MONO_DURATION = 16.0F; // Duración total de la carga monocromática
|
||||||
static constexpr float LOADING_COLOR_DURATION = 4.0F; // Duración total de la carga en color
|
static constexpr float LOADING_COLOR_DURATION = 4.0F; // Duración total de la carga en color
|
||||||
static constexpr float DATA2_DURATION = 5.0F; // Datos
|
static constexpr float DATA2_DURATION = 5.0F; // Datos
|
||||||
|
|
||||||
// --- Constantes de geometría ---
|
// --- Constantes de geometría ---
|
||||||
static constexpr int MONO_TOTAL_LINES = 192; // Total de líneas en carga monocromática
|
static constexpr int MONO_TOTAL_LINES = 192; // Total de líneas en carga monocromática
|
||||||
static constexpr int MONO_STEPS_PER_LINE = 5; // Pasos de animación por línea
|
static constexpr int MONO_STEPS_PER_LINE = 5; // Pasos de animación por línea
|
||||||
static constexpr int COLOR_TOTAL_BLOCKS = 768; // Total de bloques en carga color
|
static constexpr int COLOR_TOTAL_BLOCKS = 768; // Total de bloques en carga color
|
||||||
static constexpr int COLOR_BLOCK_WIDTH = 16; // Ancho del bloque de color
|
static constexpr int COLOR_BLOCK_WIDTH = 16; // Ancho del bloque de color
|
||||||
static constexpr int COLOR_BLOCK_HEIGHT = 8; // Alto del bloque de color
|
static constexpr int COLOR_BLOCK_HEIGHT = 8; // Alto del bloque de color
|
||||||
static constexpr int COLOR_BLOCKS_PER_ROW = 32; // Bloques por fila (256 / 8)
|
static constexpr int COLOR_BLOCKS_PER_ROW = 32; // Bloques por fila (256 / 8)
|
||||||
static constexpr int COLOR_BLOCK_SPACING = 8; // Espaciado entre bloques
|
static constexpr int COLOR_BLOCK_SPACING = 8; // Espaciado entre bloques
|
||||||
static constexpr int HEADER_DATAROW_HEIGHT = 9.0F; // Alto de las barras del borde de la carga de las cabeceras
|
static constexpr int HEADER_DATAROW_HEIGHT = 9.0F; // Alto de las barras del borde de la carga de las cabeceras
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza las variables
|
void update(); // Actualiza las variables
|
||||||
void render(); // Dibuja en pantalla
|
void render(); // Dibuja en pantalla
|
||||||
static void handleEvents(); // Comprueba el manejador de eventos
|
static void handleEvents(); // Comprueba el manejador de eventos
|
||||||
static void handleInput(); // Comprueba las entradas
|
static void handleInput(); // Comprueba las entradas
|
||||||
void updateState(float delta_time); // Actualiza el estado actual
|
void updateState(float delta_time); // Actualiza el estado actual
|
||||||
void transitionToState(State new_state); // Transiciona a un nuevo estado
|
void transitionToState(State new_state); // Transiciona a un nuevo estado
|
||||||
void updateMonoLoad(float delta_time); // Gestiona la carga monocromática (time-based)
|
void updateMonoLoad(float delta_time); // Gestiona la carga monocromática (time-based)
|
||||||
void updateColorLoad(float delta_time); // Gestiona la carga en color (time-based)
|
void updateColorLoad(float delta_time); // Gestiona la carga en color (time-based)
|
||||||
void renderBorder(); // Pinta el borde
|
void renderBorder(); // Pinta el borde
|
||||||
static void renderDataBorder(); // Dibuja el efecto de carga amarillo y azul en el borde
|
static void renderDataBorder(); // Dibuja el efecto de carga amarillo y azul en el borde
|
||||||
void renderHeaderBorder() const; // Dibuja el efecto de carga rojo y azul en el borde
|
void renderHeaderBorder() const; // Dibuja el efecto de carga rojo y azul en el borde
|
||||||
static void renderColoredBorder(PaletteColor color); // Dibuja el borde de color
|
static void renderColoredBorder(PaletteColor color); // Dibuja el borde de color
|
||||||
void initLineIndexArray(); // Inicializa el array de índices de líneas
|
void initLineIndexArray(); // Inicializa el array de índices de líneas
|
||||||
void printProgramName(); // Escribe el nombre del programa
|
void printProgramName(); // Escribe el nombre del programa
|
||||||
void updateCarrier(float delta_time); // Actualiza la portadora
|
void updateCarrier(float delta_time); // Actualiza la portadora
|
||||||
void updateSilent(float delta_time); // Actualiza el ruido durante el tiempo de silencio
|
void updateSilent(float delta_time); // Actualiza el ruido durante el tiempo de silencio
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros a recursos
|
// Objetos y punteros a recursos
|
||||||
std::shared_ptr<Surface> mono_loading_screen_surface_; // Surface con la pantalla de carga en blanco y negro
|
std::shared_ptr<Surface> mono_loading_screen_surface_; // Surface con la pantalla de carga en blanco y negro
|
||||||
std::shared_ptr<Surface> color_loading_screen_surface_; // Surface con la pantalla de carga en color
|
std::shared_ptr<Surface> color_loading_screen_surface_; // Surface con la pantalla de carga en color
|
||||||
std::unique_ptr<SurfaceSprite> mono_loading_screen_sprite_; // SurfaceSprite para manejar la textura mono_loading_screen_surface_
|
std::unique_ptr<SurfaceSprite> mono_loading_screen_sprite_; // SurfaceSprite para manejar la textura mono_loading_screen_surface_
|
||||||
std::unique_ptr<SurfaceSprite> color_loading_screen_sprite_; // SurfaceSprite para manejar la textura color_loading_screen_surface_
|
std::unique_ptr<SurfaceSprite> color_loading_screen_sprite_; // SurfaceSprite para manejar la textura color_loading_screen_surface_
|
||||||
std::unique_ptr<SurfaceSprite> program_sprite_; // SurfaceSprite para manejar la textura con el nombre del programa
|
std::unique_ptr<SurfaceSprite> program_sprite_; // SurfaceSprite para manejar la textura con el nombre del programa
|
||||||
std::shared_ptr<Surface> screen_surface_; // Surface para dibujar la pantalla de carga
|
std::shared_ptr<Surface> screen_surface_; // Surface para dibujar la pantalla de carga
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para delta time
|
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para delta time
|
||||||
|
|
||||||
// Variables de estado de la secuencia
|
// Variables de estado de la secuencia
|
||||||
State state_{State::SILENT1}; // Estado actual de la secuencia
|
State state_{State::SILENT1}; // Estado actual de la secuencia
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
Border current_border_type_{Border::NONE}; // Tipo de borde actual
|
Border current_border_type_{Border::NONE}; // Tipo de borde actual
|
||||||
|
|
||||||
// Arrays y estructuras auxiliares
|
// Arrays y estructuras auxiliares
|
||||||
std::array<int, MONO_TOTAL_LINES> line_index_; // El orden en el que se procesan las 192 líneas de la pantalla de carga
|
std::array<int, MONO_TOTAL_LINES> line_index_; // El orden en el que se procesan las 192 líneas de la pantalla de carga
|
||||||
SDL_FRect load_rect_{0.0F, 0.0F, 0.0F, 1.0F}; // Rectángulo para dibujar la pantalla de carga
|
SDL_FRect load_rect_{0.0F, 0.0F, 0.0F, 1.0F}; // Rectángulo para dibujar la pantalla de carga
|
||||||
Carrier carrier_; // Estructura para los efectos de la carga de cabeceras
|
Carrier carrier_; // Estructura para los efectos de la carga de cabeceras
|
||||||
Noise noise_; // Variaciones de ruido durante los silencios
|
Noise noise_; // Variaciones de ruido durante los silencios
|
||||||
|
|
||||||
// Variables de seguimiento para evitar saltos de pasos/bloques
|
// Variables de seguimiento para evitar saltos de pasos/bloques
|
||||||
int last_mono_step_{-1}; // Último paso mono dibujado
|
int last_mono_step_{-1}; // Último paso mono dibujado
|
||||||
int last_color_block_{-1}; // Último bloque color dibujado
|
int last_color_block_{-1}; // Último bloque color dibujado
|
||||||
};
|
};
|
||||||
@@ -11,68 +11,68 @@ class SurfaceSprite; // Forward declaration
|
|||||||
class Surface; // Forward declaration
|
class Surface; // Forward declaration
|
||||||
|
|
||||||
class Logo {
|
class Logo {
|
||||||
public:
|
public:
|
||||||
// --- Tipos ---
|
// --- Tipos ---
|
||||||
using EasingFunction = std::function<float(float)>; // Función de easing (permite lambdas)
|
using EasingFunction = std::function<float(float)>; // Función de easing (permite lambdas)
|
||||||
|
|
||||||
// --- Enumeraciones ---
|
// --- Enumeraciones ---
|
||||||
enum class State {
|
enum class State {
|
||||||
INITIAL, // Espera inicial
|
INITIAL, // Espera inicial
|
||||||
JAILGAMES_SLIDE_IN, // Las líneas de JAILGAMES se deslizan hacia el centro
|
JAILGAMES_SLIDE_IN, // Las líneas de JAILGAMES se deslizan hacia el centro
|
||||||
SINCE_1998_FADE_IN, // Aparición gradual del texto "Since 1998"
|
SINCE_1998_FADE_IN, // Aparición gradual del texto "Since 1998"
|
||||||
DISPLAY, // Logo completo visible
|
DISPLAY, // Logo completo visible
|
||||||
FADE_OUT, // Desaparición gradual
|
FADE_OUT, // Desaparición gradual
|
||||||
END // Fin de la secuencia
|
END // Fin de la secuencia
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Logo();
|
Logo();
|
||||||
~Logo() = default;
|
~Logo() = default;
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Constantes de tiempo (en segundos) ---
|
// --- Constantes de tiempo (en segundos) ---
|
||||||
static constexpr float INITIAL_DELAY = 0.5F; // Tiempo antes de que empiece la animación
|
static constexpr float INITIAL_DELAY = 0.5F; // Tiempo antes de que empiece la animación
|
||||||
static constexpr float SINCE_1998_FADE_DURATION = 0.5F; // Duración del fade-in de "Since 1998"
|
static constexpr float SINCE_1998_FADE_DURATION = 0.5F; // Duración del fade-in de "Since 1998"
|
||||||
static constexpr float DISPLAY_DURATION = 3.5F; // Tiempo que el logo permanece visible
|
static constexpr float DISPLAY_DURATION = 3.5F; // Tiempo que el logo permanece visible
|
||||||
static constexpr float FADE_OUT_DURATION = 0.5F; // Duración del fade-out final
|
static constexpr float FADE_OUT_DURATION = 0.5F; // Duración del fade-out final
|
||||||
|
|
||||||
// --- Constantes de animación ---
|
// --- Constantes de animación ---
|
||||||
static constexpr float JAILGAMES_SLIDE_DURATION = 0.8F; // Duración de la animación de slide-in (segundos)
|
static constexpr float JAILGAMES_SLIDE_DURATION = 0.8F; // Duración de la animación de slide-in (segundos)
|
||||||
static constexpr int JAILGAMES_DEST_X = 37; // Posición X de destino para JAILGAMES
|
static constexpr int JAILGAMES_DEST_X = 37; // Posición X de destino para JAILGAMES
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza las variables
|
void update(); // Actualiza las variables
|
||||||
void render(); // Dibuja en pantalla
|
void render(); // Dibuja en pantalla
|
||||||
static void handleEvents(); // Comprueba el manejador de eventos
|
static void handleEvents(); // Comprueba el manejador de eventos
|
||||||
static void handleInput(); // Comprueba las entradas
|
static void handleInput(); // Comprueba las entradas
|
||||||
void updateJAILGAMES(float delta_time); // Gestiona el logo de JAILGAME (time-based)
|
void updateJAILGAMES(float delta_time); // Gestiona el logo de JAILGAME (time-based)
|
||||||
void updateTextureColors(); // Gestiona el color de las texturas
|
void updateTextureColors(); // Gestiona el color de las texturas
|
||||||
void updateState(float delta_time); // Actualiza el estado actual
|
void updateState(float delta_time); // Actualiza el estado actual
|
||||||
void transitionToState(State new_state); // Transiciona a un nuevo estado
|
void transitionToState(State new_state); // Transiciona a un nuevo estado
|
||||||
[[nodiscard]] auto getColorIndex(float progress) const -> int; // Calcula el índice de color según el progreso (0.0-1.0)
|
[[nodiscard]] auto getColorIndex(float progress) const -> int; // Calcula el índice de color según el progreso (0.0-1.0)
|
||||||
static void endSection(); // Termina la sección
|
static void endSection(); // Termina la sección
|
||||||
void initColors(); // Inicializa el vector de colores
|
void initColors(); // Inicializa el vector de colores
|
||||||
void initSprites(); // Crea los sprites de cada linea
|
void initSprites(); // Crea los sprites de cada linea
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros a recursos
|
// Objetos y punteros a recursos
|
||||||
std::shared_ptr<Surface> jailgames_surface_; // Textura con los graficos "JAILGAMES"
|
std::shared_ptr<Surface> jailgames_surface_; // Textura con los graficos "JAILGAMES"
|
||||||
std::shared_ptr<Surface> since_1998_surface_; // Textura con los graficos "Since 1998"
|
std::shared_ptr<Surface> since_1998_surface_; // Textura con los graficos "Since 1998"
|
||||||
std::vector<std::shared_ptr<SurfaceSprite>> jailgames_sprite_; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
|
std::vector<std::shared_ptr<SurfaceSprite>> jailgames_sprite_; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
|
||||||
std::vector<int> jailgames_initial_x_; // Posiciones X iniciales de cada línea (para interpolación con easing)
|
std::vector<int> jailgames_initial_x_; // Posiciones X iniciales de cada línea (para interpolación con easing)
|
||||||
std::shared_ptr<SurfaceSprite> since_1998_sprite_; // SSprite para manejar la textura2
|
std::shared_ptr<SurfaceSprite> since_1998_sprite_; // SSprite para manejar la textura2
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para delta time
|
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para delta time
|
||||||
|
|
||||||
// Variables de estado de colores
|
// Variables de estado de colores
|
||||||
std::vector<Uint8> color_; // Vector con los colores para el fade
|
std::vector<Uint8> color_; // Vector con los colores para el fade
|
||||||
Uint8 jailgames_color_{0}; // Color para el sprite de "JAILGAMES"
|
Uint8 jailgames_color_{0}; // Color para el sprite de "JAILGAMES"
|
||||||
Uint8 since_1998_color_{0}; // Color para el sprite de "Since 1998"
|
Uint8 since_1998_color_{0}; // Color para el sprite de "Since 1998"
|
||||||
|
|
||||||
// Variables de estado de la secuencia
|
// Variables de estado de la secuencia
|
||||||
State state_{State::INITIAL}; // Estado actual de la secuencia
|
State state_{State::INITIAL}; // Estado actual de la secuencia
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
EasingFunction easing_function_; // Función de easing para la animación del logo
|
EasingFunction easing_function_; // Función de easing para la animación del logo
|
||||||
};
|
};
|
||||||
@@ -14,120 +14,120 @@ class Surface; // Forward declaration
|
|||||||
class Text; // Forward declaration
|
class Text; // Forward declaration
|
||||||
|
|
||||||
class Title {
|
class Title {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Title();
|
Title();
|
||||||
~Title() = default;
|
~Title() = default;
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Estructuras y enumeraciones ---
|
// --- Estructuras y enumeraciones ---
|
||||||
struct Glyph {
|
struct Glyph {
|
||||||
char letter; // Letra a escribir (char es más eficiente que std::string)
|
char letter; // Letra a escribir (char es más eficiente que std::string)
|
||||||
float x; // Posición en el eje x (float para precisión con delta time)
|
float x; // Posición en el eje x (float para precisión con delta time)
|
||||||
float width; // Ancho pre-calculado del carácter
|
float width; // Ancho pre-calculado del carácter
|
||||||
bool enabled; // Solo se escriben y mueven si estan habilitadas
|
bool enabled; // Solo se escriben y mueven si estan habilitadas
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class State {
|
enum class State {
|
||||||
SHOW_LOADING_SCREEN,
|
SHOW_LOADING_SCREEN,
|
||||||
FADE_LOADING_SCREEN,
|
FADE_LOADING_SCREEN,
|
||||||
MAIN_MENU,
|
MAIN_MENU,
|
||||||
CHEEVOS_MENU,
|
CHEEVOS_MENU,
|
||||||
FADE_MENU,
|
FADE_MENU,
|
||||||
POST_FADE_MENU,
|
POST_FADE_MENU,
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes de tiempo (en segundos) ---
|
// --- Constantes de tiempo (en segundos) ---
|
||||||
static constexpr float SHOW_LOADING_DURATION = 5.0F; // Tiempo mostrando loading screen (antes 500 frames)
|
static constexpr float SHOW_LOADING_DURATION = 5.0F; // Tiempo mostrando loading screen (antes 500 frames)
|
||||||
static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade (antes cada 4 frames)
|
static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade (antes cada 4 frames)
|
||||||
static constexpr float POST_FADE_DELAY = 1.0F; // Delay después del fade (pantalla en negro)
|
static constexpr float POST_FADE_DELAY = 1.0F; // Delay después del fade (pantalla en negro)
|
||||||
static constexpr float MAIN_MENU_IDLE_TIMEOUT = 20.0F; // Timeout para ir a créditos (antes 2200 frames)
|
static constexpr float MAIN_MENU_IDLE_TIMEOUT = 20.0F; // Timeout para ir a créditos (antes 2200 frames)
|
||||||
static constexpr float KEYBOARD_REMAP_DISPLAY_DELAY = 2.0F; // Tiempo mostrando teclas definidas antes de guardar
|
static constexpr float KEYBOARD_REMAP_DISPLAY_DELAY = 2.0F; // Tiempo mostrando teclas definidas antes de guardar
|
||||||
static constexpr float MARQUEE_SPEED = 100.0F; // Velocidad de marquesina (pixels/segundo)
|
static constexpr float MARQUEE_SPEED = 100.0F; // Velocidad de marquesina (pixels/segundo)
|
||||||
static constexpr float CHEEVOS_SCROLL_MAX_SPEED = 180.0F; // Velocidad máxima de scroll de logros (pixels/segundo)
|
static constexpr float CHEEVOS_SCROLL_MAX_SPEED = 180.0F; // Velocidad máxima de scroll de logros (pixels/segundo)
|
||||||
static constexpr float CHEEVOS_SCROLL_ACCELERATION = 600.0F; // Aceleración del scroll (pixels/segundo²)
|
static constexpr float CHEEVOS_SCROLL_ACCELERATION = 600.0F; // Aceleración del scroll (pixels/segundo²)
|
||||||
static constexpr float CHEEVOS_SCROLL_DECELERATION = 800.0F; // Desaceleración del scroll (pixels/segundo²)
|
static constexpr float CHEEVOS_SCROLL_DECELERATION = 800.0F; // Desaceleración del scroll (pixels/segundo²)
|
||||||
|
|
||||||
// --- Constantes de marquesina ---
|
// --- Constantes de marquesina ---
|
||||||
static constexpr float MARQUEE_START_X = 256.0F; // Posición inicial (ancho pantalla)
|
static constexpr float MARQUEE_START_X = 256.0F; // Posición inicial (ancho pantalla)
|
||||||
static constexpr float MARQUEE_EXIT_X = -10.0F; // Cuando desaparece de pantalla
|
static constexpr float MARQUEE_EXIT_X = -10.0F; // Cuando desaparece de pantalla
|
||||||
static constexpr float MARQUEE_Y = 184.0F; // Posición Y
|
static constexpr float MARQUEE_Y = 184.0F; // Posición Y
|
||||||
static constexpr float MARQUEE_LETTER_SPACING = 1.0F; // Espaciado entre letras
|
static constexpr float MARQUEE_LETTER_SPACING = 1.0F; // Espaciado entre letras
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Métodos ---
|
||||||
void update(); // Actualiza las variables
|
void update(); // Actualiza las variables
|
||||||
void render(); // Dibuja en pantalla
|
void render(); // Dibuja en pantalla
|
||||||
void handleEvents(); // Comprueba el manejador de eventos
|
void handleEvents(); // Comprueba el manejador de eventos
|
||||||
void handleMainMenuKeyPress(SDL_Keycode key); // Maneja las teclas del menu principal
|
void handleMainMenuKeyPress(SDL_Keycode key); // Maneja las teclas del menu principal
|
||||||
void handleInput(float delta_time); // Comprueba las entradas
|
void handleInput(float delta_time); // Comprueba las entradas
|
||||||
void updateState(float delta_time); // Actualiza el estado actual
|
void updateState(float delta_time); // Actualiza el estado actual
|
||||||
void transitionToState(State new_state); // Transiciona a un nuevo estado
|
void transitionToState(State new_state); // Transiciona a un nuevo estado
|
||||||
void updateShowLoadingScreen(float delta_time); // Actualiza SHOW_LOADING_SCREEN
|
void updateShowLoadingScreen(float delta_time); // Actualiza SHOW_LOADING_SCREEN
|
||||||
void updateFadeLoadingScreen(float delta_time); // Actualiza FADE_LOADING_SCREEN
|
void updateFadeLoadingScreen(float delta_time); // Actualiza FADE_LOADING_SCREEN
|
||||||
void updateMainMenu(float delta_time); // Actualiza MAIN_MENU
|
void updateMainMenu(float delta_time); // Actualiza MAIN_MENU
|
||||||
void updateCheevosMenu(float delta_time); // Actualiza CHEEVOS_MENU
|
void updateCheevosMenu(float delta_time); // Actualiza CHEEVOS_MENU
|
||||||
void updateFadeMenu(float delta_time); // Actualiza FADE_MENU
|
void updateFadeMenu(float delta_time); // Actualiza FADE_MENU
|
||||||
void updatePostFadeMenu(float delta_time); // Actualiza POST_FADE_MENU
|
void updatePostFadeMenu(float delta_time); // Actualiza POST_FADE_MENU
|
||||||
void initMarquee(); // Inicializa la marquesina
|
void initMarquee(); // Inicializa la marquesina
|
||||||
void updateMarquee(float delta_time); // Actualiza la marquesina (time-based)
|
void updateMarquee(float delta_time); // Actualiza la marquesina (time-based)
|
||||||
void renderMarquee(); // Dibuja la marquesina
|
void renderMarquee(); // Dibuja la marquesina
|
||||||
void renderGameLogo(); // Dibuja el logo con el titulo del juego
|
void renderGameLogo(); // Dibuja el logo con el titulo del juego
|
||||||
void renderMainMenu(); // Dibuja el menu principal
|
void renderMainMenu(); // Dibuja el menu principal
|
||||||
void renderCheevosMenu(); // Dibuja el menu de logros
|
void renderCheevosMenu(); // Dibuja el menu de logros
|
||||||
void renderKeyboardRemap(); // Dibuja la pantalla de redefinir teclado
|
void renderKeyboardRemap(); // Dibuja la pantalla de redefinir teclado
|
||||||
void renderJoystickRemap(); // Dibuja la pantalla de redefinir joystick
|
void renderJoystickRemap(); // Dibuja la pantalla de redefinir joystick
|
||||||
void handleKeyboardRemap(const SDL_Event& event); // Maneja la captura de teclas
|
void handleKeyboardRemap(const SDL_Event& event); // Maneja la captura de teclas
|
||||||
void handleJoystickRemap(const SDL_Event& event); // Maneja la captura de botones del gamepad
|
void handleJoystickRemap(const SDL_Event& event); // Maneja la captura de botones del gamepad
|
||||||
static auto isKeyValid(SDL_Scancode scancode) -> bool; // Valida si una tecla es permitida
|
static auto isKeyValid(SDL_Scancode scancode) -> bool; // Valida si una tecla es permitida
|
||||||
auto isKeyDuplicate(SDL_Scancode scancode, int current_step) -> bool; // Valida si una tecla esta duplicada
|
auto isKeyDuplicate(SDL_Scancode scancode, int current_step) -> bool; // Valida si una tecla esta duplicada
|
||||||
auto isButtonDuplicate(int button, int current_step) -> bool; // Valida si un boton esta duplicado
|
auto isButtonDuplicate(int button, int current_step) -> bool; // Valida si un boton esta duplicado
|
||||||
void applyKeyboardRemap(); // Aplica y guarda las teclas redefinidas
|
void applyKeyboardRemap(); // Aplica y guarda las teclas redefinidas
|
||||||
void applyJoystickRemap(); // Aplica y guarda los botones del gamepad redefinidos
|
void applyJoystickRemap(); // Aplica y guarda los botones del gamepad redefinidos
|
||||||
static auto getActionName(int step) -> std::string; // Retorna el nombre de la accion (LEFT/RIGHT/JUMP)
|
static auto getActionName(int step) -> std::string; // Retorna el nombre de la accion (LEFT/RIGHT/JUMP)
|
||||||
static auto getButtonName(int button) -> std::string; // Retorna el nombre amigable del boton del gamepad
|
static auto getButtonName(int button) -> std::string; // Retorna el nombre amigable del boton del gamepad
|
||||||
void createCheevosTexture(); // Crea y rellena la surface para mostrar los logros
|
void createCheevosTexture(); // Crea y rellena la surface para mostrar los logros
|
||||||
void resetCheevosScroll(); // Resetea el scroll de la lista de logros
|
void resetCheevosScroll(); // Resetea el scroll de la lista de logros
|
||||||
void fillTitleSurface(); // Dibuja los elementos en la surface
|
void fillTitleSurface(); // Dibuja los elementos en la surface
|
||||||
|
|
||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Objetos y punteros
|
// Objetos y punteros
|
||||||
std::shared_ptr<Surface> game_logo_surface_; // Textura con los graficos
|
std::shared_ptr<Surface> game_logo_surface_; // Textura con los graficos
|
||||||
std::unique_ptr<SurfaceSprite> game_logo_sprite_; // SSprite para manejar la surface
|
std::unique_ptr<SurfaceSprite> game_logo_sprite_; // SSprite para manejar la surface
|
||||||
std::shared_ptr<Surface> loading_screen_surface_; // Surface con los gráficos de la pantalla de carga
|
std::shared_ptr<Surface> loading_screen_surface_; // Surface con los gráficos de la pantalla de carga
|
||||||
std::unique_ptr<SurfaceSprite> loading_screen_sprite_; // SSprite con los gráficos de la pantalla de carga
|
std::unique_ptr<SurfaceSprite> loading_screen_sprite_; // SSprite con los gráficos de la pantalla de carga
|
||||||
std::shared_ptr<Surface> cheevos_surface_; // Textura con la lista de logros
|
std::shared_ptr<Surface> cheevos_surface_; // Textura con la lista de logros
|
||||||
std::unique_ptr<SurfaceSprite> cheevos_sprite_; // SSprite para manejar la surface con la lista de logros
|
std::unique_ptr<SurfaceSprite> cheevos_sprite_; // SSprite para manejar la surface con la lista de logros
|
||||||
std::shared_ptr<Surface> title_surface_; // Surface donde se dibuja toda la clase
|
std::shared_ptr<Surface> title_surface_; // Surface donde se dibuja toda la clase
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para delta time
|
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para delta time
|
||||||
std::shared_ptr<Text> marquee_text_; // Texto para marquesina
|
std::shared_ptr<Text> marquee_text_; // Texto para marquesina
|
||||||
std::shared_ptr<Text> menu_text_; // Texto para los menus
|
std::shared_ptr<Text> menu_text_; // Texto para los menus
|
||||||
|
|
||||||
// Variables de estado de marquesina
|
// Variables de estado de marquesina
|
||||||
std::string long_text_; // Texto que aparece en la parte inferior del titulo
|
std::string long_text_; // Texto que aparece en la parte inferior del titulo
|
||||||
std::vector<Glyph> letters_; // Vector con las letras de la marquesina
|
std::vector<Glyph> letters_; // Vector con las letras de la marquesina
|
||||||
int first_active_letter_{0}; // Primera letra activa (optimización)
|
int first_active_letter_{0}; // Primera letra activa (optimización)
|
||||||
int last_active_letter_{0}; // Última letra activa (optimización)
|
int last_active_letter_{0}; // Última letra activa (optimización)
|
||||||
|
|
||||||
// Variables de estado del menú de logros
|
// Variables de estado del menú de logros
|
||||||
SDL_FRect cheevos_surface_view_; // Zona visible de la surface con el listado de logros
|
SDL_FRect cheevos_surface_view_; // Zona visible de la surface con el listado de logros
|
||||||
float cheevos_scroll_velocity_{0.0F}; // Velocidad actual del scroll de logros (pixels/segundo)
|
float cheevos_scroll_velocity_{0.0F}; // Velocidad actual del scroll de logros (pixels/segundo)
|
||||||
|
|
||||||
// Variables de estado general
|
// Variables de estado general
|
||||||
State state_; // Estado en el que se encuentra el bucle principal
|
State state_; // Estado en el que se encuentra el bucle principal
|
||||||
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
float state_time_{0.0F}; // Tiempo acumulado en el estado actual
|
||||||
float fade_accumulator_{0.0F}; // Acumulador para controlar el fade por tiempo
|
float fade_accumulator_{0.0F}; // Acumulador para controlar el fade por tiempo
|
||||||
SceneManager::Scene exit_scene_{SceneManager::Scene::GAME}; // Escena de destino al salir del título
|
SceneManager::Scene exit_scene_{SceneManager::Scene::GAME}; // Escena de destino al salir del título
|
||||||
|
|
||||||
// Variables para redefinir controles
|
// Variables para redefinir controles
|
||||||
bool is_remapping_keyboard_{false}; // True si estamos redefiniendo teclado
|
bool is_remapping_keyboard_{false}; // True si estamos redefiniendo teclado
|
||||||
bool is_remapping_joystick_{false}; // True si estamos redefiniendo joystick
|
bool is_remapping_joystick_{false}; // True si estamos redefiniendo joystick
|
||||||
int remap_step_{0}; // Paso actual en la redefinicion (0=LEFT, 1=RIGHT, 2=JUMP)
|
int remap_step_{0}; // Paso actual en la redefinicion (0=LEFT, 1=RIGHT, 2=JUMP)
|
||||||
std::array<SDL_Scancode, 3> temp_keys_; // Almacenamiento temporal de teclas capturadas
|
std::array<SDL_Scancode, 3> temp_keys_; // Almacenamiento temporal de teclas capturadas
|
||||||
std::array<int, 3> temp_buttons_; // Almacenamiento temporal de botones de gamepad capturados
|
std::array<int, 3> temp_buttons_; // Almacenamiento temporal de botones de gamepad capturados
|
||||||
std::string remap_error_message_; // Mensaje de error si la tecla/boton es invalido
|
std::string remap_error_message_; // Mensaje de error si la tecla/boton es invalido
|
||||||
float axis_cooldown_{0.0F}; // Cooldown para evitar múltiples capturas de ejes
|
float axis_cooldown_{0.0F}; // Cooldown para evitar múltiples capturas de ejes
|
||||||
bool remap_completed_{false}; // True cuando se completa el remap (mostrar antes de guardar)
|
bool remap_completed_{false}; // True cuando se completa el remap (mostrar antes de guardar)
|
||||||
};
|
};
|
||||||
@@ -11,100 +11,100 @@ class Text; // lines 9-9
|
|||||||
class DeltaTimer; // lines 11-11
|
class DeltaTimer; // lines 11-11
|
||||||
|
|
||||||
class Notifier {
|
class Notifier {
|
||||||
public:
|
public:
|
||||||
// Justificado para las notificaciones
|
// Justificado para las notificaciones
|
||||||
enum class TextAlign {
|
enum class TextAlign {
|
||||||
LEFT,
|
LEFT,
|
||||||
CENTER,
|
CENTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Forma de las notificaciones
|
// Forma de las notificaciones
|
||||||
enum class Shape {
|
enum class Shape {
|
||||||
ROUNDED,
|
ROUNDED,
|
||||||
SQUARED,
|
SQUARED,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estilo de notificación
|
// Estilo de notificación
|
||||||
struct Style {
|
struct Style {
|
||||||
Uint8 bg_color; // Color de fondo
|
Uint8 bg_color; // Color de fondo
|
||||||
Uint8 border_color; // Color del borde
|
Uint8 border_color; // Color del borde
|
||||||
Uint8 text_color; // Color del texto
|
Uint8 text_color; // Color del texto
|
||||||
Shape shape; // Forma (ROUNDED/SQUARED)
|
Shape shape; // Forma (ROUNDED/SQUARED)
|
||||||
TextAlign text_align; // Alineación del texto
|
TextAlign text_align; // Alineación del texto
|
||||||
float duration; // Duración en segundos
|
float duration; // Duración en segundos
|
||||||
std::string sound_file; // Archivo de sonido (vacío = sin sonido)
|
std::string sound_file; // Archivo de sonido (vacío = sin sonido)
|
||||||
bool play_sound; // Si reproduce sonido
|
bool play_sound; // Si reproduce sonido
|
||||||
|
|
||||||
// Estilos predefinidos
|
// Estilos predefinidos
|
||||||
static const Style DEFAULT;
|
static const Style DEFAULT;
|
||||||
static const Style CHEEVO;
|
static const Style CHEEVO;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Gestión singleton
|
// Gestión singleton
|
||||||
static void init(const std::string& icon_file, const std::string& text); // Inicialización
|
static void init(const std::string& icon_file, const std::string& text); // Inicialización
|
||||||
static void destroy(); // Destrucción
|
static void destroy(); // Destrucción
|
||||||
static auto get() -> Notifier*; // Acceso al singleton
|
static auto get() -> Notifier*; // Acceso al singleton
|
||||||
|
|
||||||
// Métodos principales
|
// Métodos principales
|
||||||
void render(); // Renderizado
|
void render(); // Renderizado
|
||||||
void update(float delta_time); // Actualización lógica
|
void update(float delta_time); // Actualización lógica
|
||||||
void show(
|
void show(
|
||||||
std::vector<std::string> texts,
|
std::vector<std::string> texts,
|
||||||
const Style& style = Style::DEFAULT,
|
const Style& style = Style::DEFAULT,
|
||||||
int icon = -1,
|
int icon = -1,
|
||||||
bool can_be_removed = true,
|
bool can_be_removed = true,
|
||||||
const std::string& code = std::string()); // Mostrar notificación
|
const std::string& code = std::string()); // Mostrar notificación
|
||||||
|
|
||||||
// Consultas
|
// Consultas
|
||||||
auto isActive() -> bool; // Indica si hay notificaciones activas
|
auto isActive() -> bool; // Indica si hay notificaciones activas
|
||||||
auto getCodes() -> std::vector<std::string>; // Obtiene códigos de notificaciones
|
auto getCodes() -> std::vector<std::string>; // Obtiene códigos de notificaciones
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Tipos anidados
|
// Tipos anidados
|
||||||
enum class Status {
|
enum class Status {
|
||||||
RISING,
|
RISING,
|
||||||
STAY,
|
STAY,
|
||||||
VANISHING,
|
VANISHING,
|
||||||
FINISHED,
|
FINISHED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Notification {
|
struct Notification {
|
||||||
std::shared_ptr<Surface> surface{nullptr};
|
std::shared_ptr<Surface> surface{nullptr};
|
||||||
std::shared_ptr<SurfaceSprite> sprite{nullptr};
|
std::shared_ptr<SurfaceSprite> sprite{nullptr};
|
||||||
std::vector<std::string> texts;
|
std::vector<std::string> texts;
|
||||||
Status state{Status::RISING};
|
Status state{Status::RISING};
|
||||||
Shape shape{Shape::SQUARED};
|
Shape shape{Shape::SQUARED};
|
||||||
SDL_FRect rect{0.0F, 0.0F, 0.0F, 0.0F};
|
SDL_FRect rect{0.0F, 0.0F, 0.0F, 0.0F};
|
||||||
int y{0};
|
int y{0};
|
||||||
int travel_dist{0};
|
int travel_dist{0};
|
||||||
std::string code;
|
std::string code;
|
||||||
bool can_be_removed{true};
|
bool can_be_removed{true};
|
||||||
int height{0};
|
int height{0};
|
||||||
float elapsed_time{0.0F};
|
float elapsed_time{0.0F};
|
||||||
float display_duration{0.0F};
|
float display_duration{0.0F};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constantes
|
// Constantes
|
||||||
static constexpr float ICON_SIZE = 16.0F;
|
static constexpr float ICON_SIZE = 16.0F;
|
||||||
static constexpr float PADDING_OUT = 0.0F;
|
static constexpr float PADDING_OUT = 0.0F;
|
||||||
static constexpr float SLIDE_SPEED = 120.0F; // Pixels per second for slide animations
|
static constexpr float SLIDE_SPEED = 120.0F; // Pixels per second for slide animations
|
||||||
|
|
||||||
// [SINGLETON] Objeto notifier
|
// [SINGLETON] Objeto notifier
|
||||||
static Notifier* notifier;
|
static Notifier* notifier;
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
void clearFinishedNotifications(); // Elimina las notificaciones finalizadas
|
void clearFinishedNotifications(); // Elimina las notificaciones finalizadas
|
||||||
void clearNotifications(); // Finaliza y elimina todas las notificaciones activas
|
void clearNotifications(); // Finaliza y elimina todas las notificaciones activas
|
||||||
|
|
||||||
// Constructor y destructor privados [SINGLETON]
|
// Constructor y destructor privados [SINGLETON]
|
||||||
Notifier(const std::string& icon_file, const std::string& text);
|
Notifier(const std::string& icon_file, const std::string& text);
|
||||||
~Notifier() = default;
|
~Notifier() = default;
|
||||||
|
|
||||||
// Variables miembro
|
// Variables miembro
|
||||||
std::shared_ptr<Surface> icon_surface_; // Textura para los iconos
|
std::shared_ptr<Surface> icon_surface_; // Textura para los iconos
|
||||||
std::shared_ptr<Text> text_; // Objeto para dibujar texto
|
std::shared_ptr<Text> text_; // Objeto para dibujar texto
|
||||||
std::unique_ptr<DeltaTimer> delta_timer_; // Timer for frame-independent animations
|
std::unique_ptr<DeltaTimer> delta_timer_; // Timer for frame-independent animations
|
||||||
std::vector<Notification> notifications_; // Lista de notificaciones activas
|
std::vector<Notification> notifications_; // Lista de notificaciones activas
|
||||||
bool stack_{false}; // Indica si las notificaciones se apilan
|
bool stack_{false}; // Indica si las notificaciones se apilan
|
||||||
bool has_icons_{false}; // Indica si el notificador tiene textura para iconos
|
bool has_icons_{false}; // Indica si el notificador tiene textura para iconos
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,48 +4,48 @@
|
|||||||
|
|
||||||
// Textos
|
// Textos
|
||||||
namespace Texts {
|
namespace Texts {
|
||||||
constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner";
|
constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner";
|
||||||
constexpr const char* COPYRIGHT = "@2022 JailDesigner";
|
constexpr const char* COPYRIGHT = "@2022 JailDesigner";
|
||||||
constexpr const char* VERSION = "1.10"; // Versión por defecto
|
constexpr const char* VERSION = "1.10"; // Versión por defecto
|
||||||
} // namespace Texts
|
} // namespace Texts
|
||||||
|
|
||||||
// Tamaño de bloque
|
// Tamaño de bloque
|
||||||
namespace Tile {
|
namespace Tile {
|
||||||
constexpr int SIZE = 8;
|
constexpr int SIZE = 8;
|
||||||
constexpr int HALF_SIZE = SIZE / 2;
|
constexpr int HALF_SIZE = SIZE / 2;
|
||||||
} // namespace Tile
|
} // namespace Tile
|
||||||
|
|
||||||
namespace PlayArea {
|
namespace PlayArea {
|
||||||
constexpr int TOP = (0 * Tile::SIZE);
|
constexpr int TOP = (0 * Tile::SIZE);
|
||||||
constexpr int BOTTOM = (16 * Tile::SIZE);
|
constexpr int BOTTOM = (16 * Tile::SIZE);
|
||||||
constexpr int LEFT = (0 * Tile::SIZE);
|
constexpr int LEFT = (0 * Tile::SIZE);
|
||||||
constexpr int RIGHT = (32 * Tile::SIZE);
|
constexpr int RIGHT = (32 * Tile::SIZE);
|
||||||
constexpr int WIDTH = RIGHT - LEFT;
|
constexpr int WIDTH = RIGHT - LEFT;
|
||||||
constexpr int HEIGHT = BOTTOM - TOP;
|
constexpr int HEIGHT = BOTTOM - TOP;
|
||||||
constexpr int CENTER_X = LEFT + (WIDTH / 2);
|
constexpr int CENTER_X = LEFT + (WIDTH / 2);
|
||||||
constexpr int CENTER_FIRST_QUARTER_X = (WIDTH / 4);
|
constexpr int CENTER_FIRST_QUARTER_X = (WIDTH / 4);
|
||||||
constexpr int CENTER_THIRD_QUARTER_X = (WIDTH / 4) * 3;
|
constexpr int CENTER_THIRD_QUARTER_X = (WIDTH / 4) * 3;
|
||||||
constexpr int CENTER_Y = TOP + (HEIGHT / 2);
|
constexpr int CENTER_Y = TOP + (HEIGHT / 2);
|
||||||
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
|
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
|
||||||
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
|
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
|
||||||
} // namespace PlayArea
|
} // namespace PlayArea
|
||||||
|
|
||||||
namespace GameCanvas {
|
namespace GameCanvas {
|
||||||
constexpr int WIDTH = 256;
|
constexpr int WIDTH = 256;
|
||||||
constexpr int HEIGHT = 192;
|
constexpr int HEIGHT = 192;
|
||||||
constexpr int CENTER_X = WIDTH / 2;
|
constexpr int CENTER_X = WIDTH / 2;
|
||||||
constexpr int FIRST_QUARTER_X = WIDTH / 4;
|
constexpr int FIRST_QUARTER_X = WIDTH / 4;
|
||||||
constexpr int THIRD_QUARTER_X = (WIDTH / 4) * 3;
|
constexpr int THIRD_QUARTER_X = (WIDTH / 4) * 3;
|
||||||
constexpr int CENTER_Y = HEIGHT / 2;
|
constexpr int CENTER_Y = HEIGHT / 2;
|
||||||
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
|
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
|
||||||
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
|
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
|
||||||
} // namespace GameCanvas
|
} // namespace GameCanvas
|
||||||
|
|
||||||
namespace Collision {
|
namespace Collision {
|
||||||
constexpr int NONE = -1;
|
constexpr int NONE = -1;
|
||||||
} // namespace Collision
|
} // namespace Collision
|
||||||
|
|
||||||
namespace Flip {
|
namespace Flip {
|
||||||
constexpr SDL_FlipMode LEFT = SDL_FLIP_HORIZONTAL;
|
constexpr SDL_FlipMode LEFT = SDL_FLIP_HORIZONTAL;
|
||||||
constexpr SDL_FlipMode RIGHT = SDL_FLIP_NONE;
|
constexpr SDL_FlipMode RIGHT = SDL_FLIP_NONE;
|
||||||
} // namespace Flip
|
} // namespace Flip
|
||||||
@@ -5,24 +5,24 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
class DeltaTimer {
|
class DeltaTimer {
|
||||||
public:
|
public:
|
||||||
DeltaTimer() noexcept;
|
DeltaTimer() noexcept;
|
||||||
|
|
||||||
// Calcula delta en segundos y actualiza el contador interno
|
// Calcula delta en segundos y actualiza el contador interno
|
||||||
auto tick() noexcept -> float;
|
auto tick() noexcept -> float;
|
||||||
|
|
||||||
// Devuelve el delta estimado desde el último tick sin actualizar el contador
|
// Devuelve el delta estimado desde el último tick sin actualizar el contador
|
||||||
[[nodiscard]] auto peek() const noexcept -> float;
|
[[nodiscard]] auto peek() const noexcept -> float;
|
||||||
|
|
||||||
// Reinicia el contador al valor actual o al valor pasado (en performance counter ticks)
|
// Reinicia el contador al valor actual o al valor pasado (en performance counter ticks)
|
||||||
void reset(Uint64 counter = 0) noexcept;
|
void reset(Uint64 counter = 0) noexcept;
|
||||||
|
|
||||||
// Escala el tiempo retornado por tick/peek, por defecto 1.0f
|
// Escala el tiempo retornado por tick/peek, por defecto 1.0f
|
||||||
void setTimeScale(float scale) noexcept;
|
void setTimeScale(float scale) noexcept;
|
||||||
[[nodiscard]] auto getTimeScale() const noexcept -> float;
|
[[nodiscard]] auto getTimeScale() const noexcept -> float;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Uint64 last_counter_;
|
Uint64 last_counter_;
|
||||||
double perf_freq_;
|
double perf_freq_;
|
||||||
float time_scale_;
|
float time_scale_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,230 +22,230 @@
|
|||||||
|
|
||||||
namespace Easing {
|
namespace Easing {
|
||||||
|
|
||||||
// LINEAR
|
// LINEAR
|
||||||
inline auto linear(float t) -> float {
|
inline auto linear(float t) -> float {
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// QUAD (Cuadrática: t^2)
|
|
||||||
inline auto quadIn(float t) -> float {
|
|
||||||
return t * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto quadOut(float t) -> float {
|
|
||||||
return t * (2.0F - t);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto quadInOut(float t) -> float {
|
|
||||||
if (t < 0.5F) {
|
|
||||||
return 2.0F * t * t;
|
|
||||||
}
|
|
||||||
return -1.0F + ((4.0F - 2.0F * t) * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CUBIC (Cúbica: t^3)
|
|
||||||
inline auto cubicIn(float t) -> float {
|
|
||||||
return t * t * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto cubicOut(float t) -> float {
|
|
||||||
const float F = t - 1.0F;
|
|
||||||
return (F * F * F) + 1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto cubicInOut(float t) -> float {
|
|
||||||
if (t < 0.5F) {
|
|
||||||
return 4.0F * t * t * t;
|
|
||||||
}
|
|
||||||
const float F = ((2.0F * t) - 2.0F);
|
|
||||||
return (0.5F * F * F * F) + 1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
// QUART (Cuártica: t^4)
|
|
||||||
inline auto quartIn(float t) -> float {
|
|
||||||
return t * t * t * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto quartOut(float t) -> float {
|
|
||||||
const float F = t - 1.0F;
|
|
||||||
return 1.0F - (F * F * F * F);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto quartInOut(float t) -> float {
|
|
||||||
if (t < 0.5F) {
|
|
||||||
return 8.0F * t * t * t * t;
|
|
||||||
}
|
|
||||||
const float F = t - 1.0F;
|
|
||||||
return 1.0F - (8.0F * F * F * F * F);
|
|
||||||
}
|
|
||||||
|
|
||||||
// QUINT (Quíntica: t^5)
|
|
||||||
inline auto quintIn(float t) -> float {
|
|
||||||
return t * t * t * t * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto quintOut(float t) -> float {
|
|
||||||
const float F = t - 1.0F;
|
|
||||||
return (F * F * F * F * F) + 1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto quintInOut(float t) -> float {
|
|
||||||
if (t < 0.5F) {
|
|
||||||
return 16.0F * t * t * t * t * t;
|
|
||||||
}
|
|
||||||
const float F = ((2.0F * t) - 2.0F);
|
|
||||||
return (0.5F * F * F * F * F * F) + 1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SINE (Sinusoidal)
|
|
||||||
inline auto sineIn(float t) -> float {
|
|
||||||
return 1.0F - std::cos(t * std::numbers::pi_v<float> * 0.5F);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto sineOut(float t) -> float {
|
|
||||||
return std::sin(t * std::numbers::pi_v<float> * 0.5F);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto sineInOut(float t) -> float {
|
|
||||||
return 0.5F * (1.0F - std::cos(std::numbers::pi_v<float> * t));
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPO (Exponencial)
|
|
||||||
inline auto expoIn(float t) -> float {
|
|
||||||
if (t == 0.0F) {
|
|
||||||
return 0.0F;
|
|
||||||
}
|
|
||||||
return std::pow(2.0F, 10.0F * (t - 1.0F));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto expoOut(float t) -> float {
|
|
||||||
if (t == 1.0F) {
|
|
||||||
return 1.0F;
|
|
||||||
}
|
|
||||||
return 1.0F - std::pow(2.0F, -10.0F * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto expoInOut(float t) -> float {
|
|
||||||
if (t == 0.0F || t == 1.0F) {
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t < 0.5F) {
|
// QUAD (Cuadrática: t^2)
|
||||||
return 0.5F * std::pow(2.0F, (20.0F * t) - 10.0F);
|
inline auto quadIn(float t) -> float {
|
||||||
}
|
return t * t;
|
||||||
return 0.5F * (2.0F - std::pow(2.0F, (-20.0F * t) + 10.0F));
|
|
||||||
}
|
|
||||||
|
|
||||||
// CIRC (Circular)
|
|
||||||
inline auto circIn(float t) -> float {
|
|
||||||
return 1.0F - std::sqrt(1.0F - (t * t));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto circOut(float t) -> float {
|
|
||||||
const float F = t - 1.0F;
|
|
||||||
return std::sqrt(1.0F - (F * F));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto circInOut(float t) -> float {
|
|
||||||
if (t < 0.5F) {
|
|
||||||
return 0.5F * (1.0F - std::sqrt(1.0F - (4.0F * t * t)));
|
|
||||||
}
|
|
||||||
const float F = (2.0F * t) - 2.0F;
|
|
||||||
return 0.5F * (std::sqrt(1.0F - (F * F)) + 1.0F);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BACK (Overshoot - retrocede antes de avanzar)
|
|
||||||
inline auto backIn(float t, float overshoot = 1.70158F) -> float {
|
|
||||||
return t * t * ((overshoot + 1.0F) * t - overshoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto backOut(float t, float overshoot = 1.70158F) -> float {
|
|
||||||
const float F = t - 1.0F;
|
|
||||||
return (F * F * ((overshoot + 1.0F) * F + overshoot)) + 1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto backInOut(float t, float overshoot = 1.70158F) -> float {
|
|
||||||
const float S = overshoot * 1.525F;
|
|
||||||
|
|
||||||
if (t < 0.5F) {
|
|
||||||
const float F = 2.0F * t;
|
|
||||||
return 0.5F * (F * F * ((S + 1.0F) * F - S));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float F = (2.0F * t) - 2.0F;
|
inline auto quadOut(float t) -> float {
|
||||||
return 0.5F * (F * F * ((S + 1.0F) * F + S) + 2.0F);
|
return t * (2.0F - t);
|
||||||
}
|
|
||||||
|
|
||||||
// ELASTIC (Oscilación elástica - efecto de resorte)
|
|
||||||
inline auto elasticIn(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
|
|
||||||
if (t == 0.0F || t == 1.0F) {
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
|
inline auto quadInOut(float t) -> float {
|
||||||
const float F = t - 1.0F;
|
if (t < 0.5F) {
|
||||||
return -(amplitude * std::pow(2.0F, 10.0F * F) *
|
return 2.0F * t * t;
|
||||||
std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period));
|
}
|
||||||
}
|
return -1.0F + ((4.0F - 2.0F * t) * t);
|
||||||
|
|
||||||
inline auto elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
|
|
||||||
if (t == 0.0F || t == 1.0F) {
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
|
// CUBIC (Cúbica: t^3)
|
||||||
return (amplitude * std::pow(2.0F, -10.0F * t) *
|
inline auto cubicIn(float t) -> float {
|
||||||
std::sin((t - S) * (2.0F * std::numbers::pi_v<float>) / period)) +
|
return t * t * t;
|
||||||
1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
|
|
||||||
if (t == 0.0F || t == 1.0F) {
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
|
inline auto cubicOut(float t) -> float {
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return (F * F * F) + 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto cubicInOut(float t) -> float {
|
||||||
|
if (t < 0.5F) {
|
||||||
|
return 4.0F * t * t * t;
|
||||||
|
}
|
||||||
|
const float F = ((2.0F * t) - 2.0F);
|
||||||
|
return (0.5F * F * F * F) + 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// QUART (Cuártica: t^4)
|
||||||
|
inline auto quartIn(float t) -> float {
|
||||||
|
return t * t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto quartOut(float t) -> float {
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return 1.0F - (F * F * F * F);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto quartInOut(float t) -> float {
|
||||||
|
if (t < 0.5F) {
|
||||||
|
return 8.0F * t * t * t * t;
|
||||||
|
}
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return 1.0F - (8.0F * F * F * F * F);
|
||||||
|
}
|
||||||
|
|
||||||
|
// QUINT (Quíntica: t^5)
|
||||||
|
inline auto quintIn(float t) -> float {
|
||||||
|
return t * t * t * t * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto quintOut(float t) -> float {
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return (F * F * F * F * F) + 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto quintInOut(float t) -> float {
|
||||||
|
if (t < 0.5F) {
|
||||||
|
return 16.0F * t * t * t * t * t;
|
||||||
|
}
|
||||||
|
const float F = ((2.0F * t) - 2.0F);
|
||||||
|
return (0.5F * F * F * F * F * F) + 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SINE (Sinusoidal)
|
||||||
|
inline auto sineIn(float t) -> float {
|
||||||
|
return 1.0F - std::cos(t * std::numbers::pi_v<float> * 0.5F);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto sineOut(float t) -> float {
|
||||||
|
return std::sin(t * std::numbers::pi_v<float> * 0.5F);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto sineInOut(float t) -> float {
|
||||||
|
return 0.5F * (1.0F - std::cos(std::numbers::pi_v<float> * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPO (Exponencial)
|
||||||
|
inline auto expoIn(float t) -> float {
|
||||||
|
if (t == 0.0F) {
|
||||||
|
return 0.0F;
|
||||||
|
}
|
||||||
|
return std::pow(2.0F, 10.0F * (t - 1.0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto expoOut(float t) -> float {
|
||||||
|
if (t == 1.0F) {
|
||||||
|
return 1.0F;
|
||||||
|
}
|
||||||
|
return 1.0F - std::pow(2.0F, -10.0F * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto expoInOut(float t) -> float {
|
||||||
|
if (t == 0.0F || t == 1.0F) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t < 0.5F) {
|
||||||
|
return 0.5F * std::pow(2.0F, (20.0F * t) - 10.0F);
|
||||||
|
}
|
||||||
|
return 0.5F * (2.0F - std::pow(2.0F, (-20.0F * t) + 10.0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CIRC (Circular)
|
||||||
|
inline auto circIn(float t) -> float {
|
||||||
|
return 1.0F - std::sqrt(1.0F - (t * t));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto circOut(float t) -> float {
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return std::sqrt(1.0F - (F * F));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto circInOut(float t) -> float {
|
||||||
|
if (t < 0.5F) {
|
||||||
|
return 0.5F * (1.0F - std::sqrt(1.0F - (4.0F * t * t)));
|
||||||
|
}
|
||||||
|
const float F = (2.0F * t) - 2.0F;
|
||||||
|
return 0.5F * (std::sqrt(1.0F - (F * F)) + 1.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
// BACK (Overshoot - retrocede antes de avanzar)
|
||||||
|
inline auto backIn(float t, float overshoot = 1.70158F) -> float {
|
||||||
|
return t * t * ((overshoot + 1.0F) * t - overshoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto backOut(float t, float overshoot = 1.70158F) -> float {
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return (F * F * ((overshoot + 1.0F) * F + overshoot)) + 1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto backInOut(float t, float overshoot = 1.70158F) -> float {
|
||||||
|
const float S = overshoot * 1.525F;
|
||||||
|
|
||||||
|
if (t < 0.5F) {
|
||||||
|
const float F = 2.0F * t;
|
||||||
|
return 0.5F * (F * F * ((S + 1.0F) * F - S));
|
||||||
|
}
|
||||||
|
|
||||||
|
const float F = (2.0F * t) - 2.0F;
|
||||||
|
return 0.5F * (F * F * ((S + 1.0F) * F + S) + 2.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ELASTIC (Oscilación elástica - efecto de resorte)
|
||||||
|
inline auto elasticIn(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
|
||||||
|
if (t == 0.0F || t == 1.0F) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
|
||||||
|
const float F = t - 1.0F;
|
||||||
|
return -(amplitude * std::pow(2.0F, 10.0F * F) *
|
||||||
|
std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
|
||||||
|
if (t == 0.0F || t == 1.0F) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
|
||||||
|
return (amplitude * std::pow(2.0F, -10.0F * t) *
|
||||||
|
std::sin((t - S) * (2.0F * std::numbers::pi_v<float>) / period)) +
|
||||||
|
1.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
|
||||||
|
if (t == 0.0F || t == 1.0F) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float S = period / (2.0F * std::numbers::pi_v<float>)*std::asin(1.0F / amplitude);
|
||||||
|
|
||||||
|
if (t < 0.5F) {
|
||||||
|
const float F = (2.0F * t) - 1.0F;
|
||||||
|
return -0.5F * (amplitude * std::pow(2.0F, 10.0F * F) * std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period));
|
||||||
|
}
|
||||||
|
|
||||||
if (t < 0.5F) {
|
|
||||||
const float F = (2.0F * t) - 1.0F;
|
const float F = (2.0F * t) - 1.0F;
|
||||||
return -0.5F * (amplitude * std::pow(2.0F, 10.0F * F) * std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period));
|
return (0.5F * amplitude * std::pow(2.0F, -10.0F * F) *
|
||||||
|
std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period)) +
|
||||||
|
1.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float F = (2.0F * t) - 1.0F;
|
// BOUNCE (Rebote - simula física de rebote)
|
||||||
return (0.5F * amplitude * std::pow(2.0F, -10.0F * F) *
|
inline auto bounceOut(float t) -> float {
|
||||||
std::sin((F - S) * (2.0F * std::numbers::pi_v<float>) / period)) +
|
const float N1 = 7.5625F;
|
||||||
1.0F;
|
const float D1 = 2.75F;
|
||||||
}
|
|
||||||
|
|
||||||
// BOUNCE (Rebote - simula física de rebote)
|
if (t < 1.0F / D1) {
|
||||||
inline auto bounceOut(float t) -> float {
|
return N1 * t * t;
|
||||||
const float N1 = 7.5625F;
|
}
|
||||||
const float D1 = 2.75F;
|
if (t < 2.0F / D1) {
|
||||||
|
const float F = t - (1.5F / D1);
|
||||||
|
return (N1 * F * F) + 0.75F;
|
||||||
|
}
|
||||||
|
if (t < 2.5F / D1) {
|
||||||
|
const float F = t - (2.25F / D1);
|
||||||
|
return (N1 * F * F) + 0.9375F;
|
||||||
|
}
|
||||||
|
const float F = t - (2.625F / D1);
|
||||||
|
return (N1 * F * F) + 0.984375F;
|
||||||
|
}
|
||||||
|
|
||||||
if (t < 1.0F / D1) {
|
inline auto bounceIn(float t) -> float {
|
||||||
return N1 * t * t;
|
return 1.0F - bounceOut(1.0F - t);
|
||||||
}
|
}
|
||||||
if (t < 2.0F / D1) {
|
|
||||||
const float F = t - (1.5F / D1);
|
|
||||||
return (N1 * F * F) + 0.75F;
|
|
||||||
}
|
|
||||||
if (t < 2.5F / D1) {
|
|
||||||
const float F = t - (2.25F / D1);
|
|
||||||
return (N1 * F * F) + 0.9375F;
|
|
||||||
}
|
|
||||||
const float F = t - (2.625F / D1);
|
|
||||||
return (N1 * F * F) + 0.984375F;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto bounceIn(float t) -> float {
|
inline auto bounceInOut(float t) -> float {
|
||||||
return 1.0F - bounceOut(1.0F - t);
|
if (t < 0.5F) {
|
||||||
}
|
return 0.5F * bounceIn(2.0F * t);
|
||||||
|
}
|
||||||
inline auto bounceInOut(float t) -> float {
|
return (0.5F * bounceOut((2.0F * t) - 1.0F)) + 0.5F;
|
||||||
if (t < 0.5F) {
|
|
||||||
return 0.5F * bounceIn(2.0F * t);
|
|
||||||
}
|
}
|
||||||
return (0.5F * bounceOut((2.0F * t) - 1.0F)) + 0.5F;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Easing
|
} // namespace Easing
|
||||||
|
|||||||
@@ -35,42 +35,42 @@ enum class PaletteColor : Uint8 {
|
|||||||
|
|
||||||
// Estructura para definir un circulo
|
// Estructura para definir un circulo
|
||||||
struct Circle {
|
struct Circle {
|
||||||
int x{0};
|
int x{0};
|
||||||
int y{0};
|
int y{0};
|
||||||
int r{0};
|
int r{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para definir una linea horizontal
|
// Estructura para definir una linea horizontal
|
||||||
struct LineHorizontal {
|
struct LineHorizontal {
|
||||||
int x1{0}, x2{0}, y{0};
|
int x1{0}, x2{0}, y{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para definir una linea vertical
|
// Estructura para definir una linea vertical
|
||||||
struct LineVertical {
|
struct LineVertical {
|
||||||
int x{0}, y1{0}, y2{0};
|
int x{0}, y1{0}, y2{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para definir una linea diagonal
|
// Estructura para definir una linea diagonal
|
||||||
struct LineDiagonal {
|
struct LineDiagonal {
|
||||||
int x1{0}, y1{0}, x2{0}, y2{0};
|
int x1{0}, y1{0}, x2{0}, y2{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para definir una linea
|
// Estructura para definir una linea
|
||||||
struct Line {
|
struct Line {
|
||||||
int x1{0}, y1{0}, x2{0}, y2{0};
|
int x1{0}, y1{0}, x2{0}, y2{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para definir un color
|
// Estructura para definir un color
|
||||||
struct Color {
|
struct Color {
|
||||||
Uint8 r{0};
|
Uint8 r{0};
|
||||||
Uint8 g{0};
|
Uint8 g{0};
|
||||||
Uint8 b{0};
|
Uint8 b{0};
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Color(Uint8 red, Uint8 green, Uint8 blue)
|
Color(Uint8 red, Uint8 green, Uint8 blue)
|
||||||
: r(red),
|
: r(red),
|
||||||
g(green),
|
g(green),
|
||||||
b(blue) {}
|
b(blue) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// COLISIONES Y GEOMETRÍA
|
// COLISIONES Y GEOMETRÍA
|
||||||
|
|||||||
Reference in New Issue
Block a user