Compare commits

2 Commits

Author SHA1 Message Date
366c00fd22 clang-format 2026-03-21 23:19:15 +01:00
55b58ded70 clang-tidy 2026-03-21 23:08:07 +01:00
79 changed files with 5666 additions and 5727 deletions

View File

@@ -1,6 +1,7 @@
BasedOnStyle: Google
IndentWidth: 4
IndentAccessModifiers: true
NamespaceIndentation: All
IndentAccessModifiers: false
ColumnLimit: 0 # Sin límite de longitud de línea
BreakBeforeBraces: Attach # Llaves en la misma línea
AllowShortIfStatementsOnASingleLine: true

View File

@@ -216,6 +216,7 @@ list(FILTER ALL_SOURCE_FILES EXCLUDE REGEX ".*/external/.*")
# Para clang-tidy, también excluir jail_audio.hpp
set(CLANG_TIDY_SOURCES ${ALL_SOURCE_FILES})
list(FILTER CLANG_TIDY_SOURCES EXCLUDE REGEX ".*jail_audio\\.hpp$")
list(FILTER CLANG_TIDY_SOURCES EXCLUDE REGEX ".*_spv\\.h$")
# Targets de clang-tidy
if(CLANG_TIDY_EXE)

View File

@@ -18,9 +18,9 @@
namespace GlobalInputs {
// Funciones internas
namespace {
void handleQuit() {
// Funciones internas
namespace {
void handleQuit() {
// En la escena GAME el comportamiento es siempre el mismo (con o sin modo kiosko)
if (SceneManager::current == SceneManager::Scene::GAME) {
const std::string CODE = "PRESS AGAIN TO RETURN TO MENU";
@@ -49,9 +49,9 @@ void handleQuit() {
} else {
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
}
}
}
void handleSkipSection() {
void handleSkipSection() {
switch (SceneManager::current) {
case SceneManager::Scene::LOGO:
case SceneManager::Scene::LOADING_SCREEN:
@@ -67,68 +67,68 @@ void handleSkipSection() {
default:
break;
}
}
}
void handleToggleBorder() {
void handleToggleBorder() {
Screen::get()->toggleBorder();
Notifier::get()->show({"BORDER " + std::string(Options::video.border.enabled ? "ENABLED" : "DISABLED")});
}
}
void handleToggleVideoMode() {
void handleToggleVideoMode() {
Screen::get()->toggleVideoMode();
Notifier::get()->show({"FULLSCREEN " + std::string(static_cast<int>(Options::video.fullscreen) == 0 ? "DISABLED" : "ENABLED")});
}
}
void handleDecWindowZoom() {
void handleDecWindowZoom() {
if (Screen::get()->decWindowZoom()) {
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
}
}
}
void handleIncWindowZoom() {
void handleIncWindowZoom() {
if (Screen::get()->incWindowZoom()) {
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
}
}
}
void handleTogglePostFX() {
void handleTogglePostFX() {
Screen::get()->togglePostFX();
Notifier::get()->show({"POSTFX " + std::string(Options::video.postfx ? "ENABLED" : "DISABLED")});
}
}
void handleNextPostFXPreset() {
void handleNextPostFXPreset() {
if (!Options::postfx_presets.empty()) {
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 handleNextPalette() {
void handleNextPalette() {
Screen::get()->nextPalette();
Notifier::get()->show({"PALETTE " + Options::video.palette});
}
}
void handlePreviousPalette() {
void handlePreviousPalette() {
Screen::get()->previousPalette();
Notifier::get()->show({"PALETTE " + Options::video.palette});
}
}
void handleToggleIntegerScale() {
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() {
void handleToggleVSync() {
Screen::get()->toggleVSync();
Notifier::get()->show({"V-SYNC " + std::string(Options::video.vertical_sync ? "ENABLED" : "DISABLED")});
}
}
#ifdef _DEBUG
void handleShowDebugInfo() {
void handleShowDebugInfo() {
Screen::get()->toggleDebugInfo();
}
}
/*
void handleToggleDebug() {
@@ -138,8 +138,8 @@ void handleToggleDebug() {
*/
#endif
// Detecta qué acción global ha sido presionada (si alguna)
auto getPressedAction() -> InputAction {
// Detecta qué acción global ha sido presionada (si alguna)
auto getPressedAction() -> InputAction {
if (Input::get()->checkAction(InputAction::EXIT, Input::DO_NOT_ALLOW_REPEAT)) {
return InputAction::EXIT;
}
@@ -161,7 +161,7 @@ auto getPressedAction() -> InputAction {
}
}
if (Input::get()->checkAction(InputAction::TOGGLE_POSTFX, Input::DO_NOT_ALLOW_REPEAT)) {
if (Options::video.postfx && (SDL_GetModState() & SDL_KMOD_SHIFT)) {
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
return InputAction::NEXT_POSTFX_PRESET;
}
return InputAction::TOGGLE_POSTFX;
@@ -185,19 +185,19 @@ auto getPressedAction() -> InputAction {
return InputAction::SHOW_DEBUG_INFO;
}
return InputAction::NONE;
}
}
} // namespace
} // namespace
// Funciones públicas
// Funciones públicas
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void handle() {
// 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) && (mod & SDL_KMOD_SHIFT) && (mod & SDL_KMOD_ALT) && ks[SDL_SCANCODE_Q]) {
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;
}
@@ -271,5 +271,5 @@ void handle() {
// No se presionó ninguna acción global
break;
}
}
}
} // namespace GlobalInputs

View File

@@ -1,6 +1,6 @@
#pragma once
namespace GlobalInputs {
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void handle();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void handle();
} // namespace GlobalInputs

View File

@@ -1,11 +1,11 @@
#include "core/input/mouse.hpp"
namespace Mouse {
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ó
bool cursor_visible = true; // Estado del 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ó
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) {
last_mouse_move_time = SDL_GetTicks();
if (!cursor_visible) {
@@ -13,13 +13,13 @@ void handleEvent(const SDL_Event& event) {
cursor_visible = true;
}
}
}
}
void updateCursorVisibility() {
void updateCursorVisibility() {
Uint32 current_time = SDL_GetTicks();
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
SDL_HideCursor();
cursor_visible = false;
}
}
}
} // namespace Mouse

View File

@@ -3,10 +3,10 @@
#include <SDL3/SDL.h>
namespace Mouse {
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 bool cursor_visible; // Estado del 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 bool cursor_visible; // Estado del cursor
void handleEvent(const SDL_Event& event);
void updateCursorVisibility();
void handleEvent(const SDL_Event& event);
void updateCursorVisibility();
} // namespace Mouse

View File

@@ -7,15 +7,15 @@
namespace GIF {
// Función inline para reemplazar el macro READ.
// Actualiza el puntero 'buffer' tras copiar 'size' bytes a 'dst'.
inline void readBytes(const uint8_t*& buffer, void* dst, size_t size) {
// Función inline para reemplazar el macro READ.
// Actualiza el puntero 'buffer' tras copiar 'size' bytes a 'dst'.
inline void readBytes(const uint8_t*& buffer, void* dst, size_t size) {
std::memcpy(dst, 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) {
// 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++) {
@@ -24,10 +24,10 @@ inline void initializeDictionary(std::vector<DictionaryEntry>& dictionary, int c
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 {
// 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) {
@@ -43,19 +43,19 @@ inline auto readNextCode(const uint8_t*& input, int& input_length, unsigned int&
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 {
// 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) {
// 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);
@@ -72,10 +72,10 @@ inline void addDictionaryEntry(std::vector<DictionaryEntry>& dictionary, int& di
code_length++;
dictionary.resize(1 << (code_length + 1));
}
}
}
// Escribe la cadena decodificada al buffer de salida
inline auto writeDecodedString(const std::vector<DictionaryEntry>& dictionary, int code, uint8_t*& out) -> int {
// 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) {
@@ -88,9 +88,9 @@ inline auto writeDecodedString(const std::vector<DictionaryEntry>& dictionary, i
}
out += match_len;
return match_len;
}
}
void Gif::decompress(int code_length, const uint8_t* input, int input_length, uint8_t* out) {
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");
@@ -144,9 +144,9 @@ void Gif::decompress(int code_length, const uint8_t* input, int input_length, ui
writeDecodedString(dictionary, code, out);
}
}
}
auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> {
auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> {
std::vector<uint8_t> data;
uint8_t block_size = *buffer;
buffer++;
@@ -157,9 +157,9 @@ auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> {
buffer++;
}
return data;
}
}
auto Gif::processImageDescriptor(const uint8_t*& buffer, const std::vector<RGB>& gct, int resolution_bits) -> std::vector<uint8_t> {
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));
@@ -173,9 +173,9 @@ auto Gif::processImageDescriptor(const uint8_t*& buffer, const std::vector<RGB>&
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> {
auto Gif::loadPalette(const uint8_t* buffer) -> std::vector<uint32_t> {
uint8_t header[6];
std::memcpy(header, buffer, 6);
buffer += 6;
@@ -197,9 +197,9 @@ auto Gif::loadPalette(const uint8_t* buffer) -> std::vector<uint32_t> {
}
}
return global_color_table;
}
}
auto Gif::processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> std::vector<uint8_t> {
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);
@@ -286,10 +286,10 @@ auto Gif::processGifStream(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> s
}
return std::vector<uint8_t>{};
}
}
auto Gif::loadGif(const uint8_t* buffer, uint16_t& w, uint16_t& h) -> 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

View File

@@ -5,66 +5,66 @@
namespace GIF {
// Constantes definidas con constexpr, en lugar de macros
constexpr uint8_t EXTENSION_INTRODUCER = 0x21;
constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C;
constexpr uint8_t TRAILER = 0x3B;
constexpr uint8_t GRAPHIC_CONTROL = 0xF9;
constexpr uint8_t APPLICATION_EXTENSION = 0xFF;
constexpr uint8_t COMMENT_EXTENSION = 0xFE;
constexpr uint8_t PLAINTEXT_EXTENSION = 0x01;
// Constantes definidas con constexpr, en lugar de macros
constexpr uint8_t EXTENSION_INTRODUCER = 0x21;
constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C;
constexpr uint8_t TRAILER = 0x3B;
constexpr uint8_t GRAPHIC_CONTROL = 0xF9;
constexpr uint8_t APPLICATION_EXTENSION = 0xFF;
constexpr uint8_t COMMENT_EXTENSION = 0xFE;
constexpr uint8_t PLAINTEXT_EXTENSION = 0x01;
#pragma pack(push, 1)
struct ScreenDescriptor {
struct ScreenDescriptor {
uint16_t width;
uint16_t height;
uint8_t fields;
uint8_t background_color_index;
uint8_t pixel_aspect_ratio;
};
};
struct RGB {
struct RGB {
uint8_t r, g, b;
};
};
struct ImageDescriptor {
struct ImageDescriptor {
uint16_t image_left_position;
uint16_t image_top_position;
uint16_t image_width;
uint16_t image_height;
uint8_t fields;
};
};
#pragma pack(pop)
struct DictionaryEntry {
struct DictionaryEntry {
uint8_t byte;
int prev;
int len;
};
};
struct Extension {
struct Extension {
uint8_t extension_code;
uint8_t block_size;
};
};
struct GraphicControlExtension {
struct GraphicControlExtension {
uint8_t fields;
uint16_t delay_time;
uint8_t transparent_color_index;
};
};
struct ApplicationExtension {
struct ApplicationExtension {
uint8_t application_id[8];
uint8_t version[3];
};
};
struct PlaintextExtension {
struct PlaintextExtension {
uint16_t left, top, width, height;
uint8_t cell_width, cell_height;
uint8_t foreground_color, background_color;
};
};
class Gif {
class Gif {
public:
// Descompone (uncompress) el bloque comprimido usando LZW.
// Este método puede lanzar std::runtime_error en caso de error.
@@ -87,6 +87,6 @@ class Gif {
// 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>;
};
};
} // namespace GIF

View File

@@ -1,6 +1,6 @@
#include "core/rendering/pixel_reveal.hpp"
#include <algorithm> // Para min
#include <algorithm> // Para min, ranges::all_of
#include <numeric> // Para iota
#include <queue> // Para queue (BFS en modo ORDERED)
#include <random> // Para mt19937, shuffle
@@ -30,7 +30,7 @@ PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float s
std::vector<int> offsets;
offsets.push_back(0);
std::queue<std::pair<int, int>> bq;
bq.push({0, num_steps_});
bq.emplace(0, num_steps_);
while (static_cast<int>(offsets.size()) < num_steps_) {
auto [lo, hi] = bq.front();
bq.pop();
@@ -39,14 +39,14 @@ PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float s
}
const int MID = (lo + hi) / 2;
offsets.push_back(MID);
bq.push({lo, MID});
bq.push({MID, hi});
bq.emplace(lo, MID);
bq.emplace(MID, hi);
}
// Genera el orden: para cada offset, todas las columnas col = offset, offset+N, offset+2N, ...
std::vector<int> ordered_cols;
ordered_cols.reserve(width_);
for (const int off : offsets) {
for (int col = off; col < width_; col += num_steps_) {
for (const int OFF : offsets) {
for (int col = OFF; col < width_; col += num_steps_) {
ordered_cols.push_back(col);
}
}
@@ -105,11 +105,6 @@ void PixelReveal::render(int dst_x, int dst_y) const {
}
// Indica si el revelado ha completado todas las filas
bool PixelReveal::isComplete() const {
for (const int step : row_step_) {
if (step < num_steps_) {
return false;
}
}
return true;
auto PixelReveal::isComplete() const -> bool {
return std::ranges::all_of(row_step_, [this](int s) { return s >= num_steps_; });
}

View File

@@ -26,7 +26,7 @@ class PixelReveal {
void render(int dst_x, int dst_y) const;
// Indica si el revelado ha completado todas las filas
[[nodiscard]] bool isComplete() const;
[[nodiscard]] auto isComplete() const -> bool;
private:
std::shared_ptr<Surface> cover_surface_; // Máscara negra que se va haciendo transparente

View File

@@ -392,7 +392,7 @@ auto Screen::findPalette(const std::string& name) -> size_t {
}
// Muestra información por pantalla
void Screen::renderInfo() {
void Screen::renderInfo() const {
if (show_debug_info_ && (Resource::Cache::get() != nullptr)) {
auto text = Resource::Cache::get()->getText("smb2");
auto color = static_cast<Uint8>(PaletteColor::YELLOW);
@@ -459,7 +459,7 @@ auto loadData(const std::string& filepath) -> std::vector<uint8_t> {
void Screen::applyCurrentPostFXPreset() {
if (shader_backend_ && !Options::postfx_presets.empty()) {
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)];
Rendering::PostFXParams params{p.vignette, p.scanlines, p.chroma, p.mask, p.gamma, p.curvature, p.bleeding};
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding};
shader_backend_->setPostFXParams(params);
}
}

View File

@@ -12,7 +12,7 @@
class Surface;
class Text;
namespace Rendering {
class ShaderBackend;
class ShaderBackend;
}
class Screen {
@@ -116,7 +116,7 @@ class Screen {
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
void initShaders(); // Inicializa los shaders
void applyCurrentPostFXPreset(); // Aplica los parámetros del preset actual al backend
void renderInfo(); // Muestra información por pantalla
void renderInfo() const; // Muestra información por pantalla
void getDisplayInfo(); // Obtiene información sobre la pantalla
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
void createText(); // Crea el objeto de texto

View File

@@ -162,17 +162,17 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
namespace Rendering {
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
SDL3GPUShader::~SDL3GPUShader() {
// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
SDL3GPUShader::~SDL3GPUShader() {
destroy();
}
}
// ---------------------------------------------------------------------------
// init
// ---------------------------------------------------------------------------
auto SDL3GPUShader::init(SDL_Window* window,
// ---------------------------------------------------------------------------
// init
// ---------------------------------------------------------------------------
auto SDL3GPUShader::init(SDL_Window* window,
SDL_Texture* texture,
const std::string& /*vertex_source*/,
const std::string& /*fragment_source*/) -> bool {
@@ -281,12 +281,12 @@ auto SDL3GPUShader::init(SDL_Window* window,
is_initialized_ = true;
SDL_Log("SDL3GPUShader: initialized OK (%dx%d)", tex_width_, tex_height_);
return true;
}
}
// ---------------------------------------------------------------------------
// createPipeline
// ---------------------------------------------------------------------------
auto SDL3GPUShader::createPipeline() -> bool {
// ---------------------------------------------------------------------------
// createPipeline
// ---------------------------------------------------------------------------
auto SDL3GPUShader::createPipeline() -> bool {
const SDL_GPUTextureFormat SWAPCHAIN_FMT = SDL_GetGPUSwapchainTextureFormat(device_, window_);
#ifdef __APPLE__
@@ -332,12 +332,12 @@ auto SDL3GPUShader::createPipeline() -> bool {
return false;
}
return true;
}
}
// ---------------------------------------------------------------------------
// uploadPixels — copies ARGB8888 CPU pixels into the GPU transfer buffer
// ---------------------------------------------------------------------------
void SDL3GPUShader::uploadPixels(const Uint32* pixels, int width, int height) {
// ---------------------------------------------------------------------------
// 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);
@@ -347,12 +347,12 @@ void SDL3GPUShader::uploadPixels(const Uint32* pixels, int width, int height) {
}
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() {
// ---------------------------------------------------------------------------
// render — upload scene texture + PostFX pass → swapchain
// ---------------------------------------------------------------------------
void SDL3GPUShader::render() {
if (!is_initialized_) { return; }
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_);
@@ -412,15 +412,15 @@ void SDL3GPUShader::render() {
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);
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(
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;
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);
@@ -439,12 +439,12 @@ void SDL3GPUShader::render() {
}
SDL_SubmitGPUCommandBuffer(cmd);
}
}
// ---------------------------------------------------------------------------
// cleanup — libera pipeline/texturas/buffer pero mantiene device + swapchain
// ---------------------------------------------------------------------------
void SDL3GPUShader::cleanup() {
// ---------------------------------------------------------------------------
// cleanup — libera pipeline/texturas/buffer pero mantiene device + swapchain
// ---------------------------------------------------------------------------
void SDL3GPUShader::cleanup() {
is_initialized_ = false;
if (device_ != nullptr) {
@@ -468,12 +468,12 @@ void SDL3GPUShader::cleanup() {
}
// device_ y el claim de la ventana se mantienen vivos
}
}
}
// ---------------------------------------------------------------------------
// destroy — limpieza completa incluyendo device y swapchain (solo al cerrar)
// ---------------------------------------------------------------------------
void SDL3GPUShader::destroy() {
// ---------------------------------------------------------------------------
// destroy — limpieza completa incluyendo device y swapchain (solo al cerrar)
// ---------------------------------------------------------------------------
void SDL3GPUShader::destroy() {
cleanup();
if (device_ != nullptr) {
@@ -484,12 +484,12 @@ void SDL3GPUShader::destroy() {
device_ = nullptr;
}
window_ = nullptr;
}
}
// ---------------------------------------------------------------------------
// Shader creation helpers
// ---------------------------------------------------------------------------
auto SDL3GPUShader::createShaderMSL(SDL_GPUDevice* device,
// ---------------------------------------------------------------------------
// Shader creation helpers
// ---------------------------------------------------------------------------
auto SDL3GPUShader::createShaderMSL(SDL_GPUDevice* device,
const char* msl_source,
const char* entrypoint,
SDL_GPUShaderStage stage,
@@ -508,9 +508,9 @@ auto SDL3GPUShader::createShaderMSL(SDL_GPUDevice* device,
SDL_Log("SDL3GPUShader: MSL shader '%s' failed: %s", entrypoint, SDL_GetError());
}
return shader;
}
}
auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device,
auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device,
const uint8_t* spv_code,
size_t spv_size,
const char* entrypoint,
@@ -530,9 +530,9 @@ auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device,
SDL_Log("SDL3GPUShader: SPIRV shader '%s' failed: %s", entrypoint, SDL_GetError());
}
return shader;
}
}
void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
uniforms_.vignette_strength = p.vignette;
uniforms_.scanline_strength = p.scanlines;
uniforms_.chroma_strength = p.chroma;
@@ -540,17 +540,17 @@ void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
uniforms_.gamma_strength = p.gamma;
uniforms_.curvature = p.curvature;
uniforms_.bleeding = p.bleeding;
}
}
void SDL3GPUShader::setVSync(bool vsync) {
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) {
void SDL3GPUShader::setScaleMode(bool integer_scale) {
integer_scale_ = integer_scale;
}
}
} // namespace Rendering

View File

@@ -21,14 +21,14 @@ struct PostFXUniforms {
namespace Rendering {
/**
/**
* @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.
* Pipeline: Surface pixels (CPU) → SDL_GPUTransferBuffer → SDL_GPUTexture (scene)
* → PostFX render pass → swapchain → present
*/
class SDL3GPUShader : public ShaderBackend {
class SDL3GPUShader : public ShaderBackend {
public:
SDL3GPUShader() = default;
~SDL3GPUShader() override;
@@ -40,7 +40,7 @@ class SDL3GPUShader : public ShaderBackend {
void render() override;
void setTextureSize(float width, float height) override {}
void cleanup() override; // 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
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
@@ -88,6 +88,6 @@ class SDL3GPUShader : public ShaderBackend {
bool is_initialized_ = false;
bool vsync_ = true;
bool integer_scale_ = false;
};
};
} // namespace Rendering

View File

@@ -6,11 +6,11 @@
namespace Rendering {
/**
/**
* @brief Parámetros de intensidad de los efectos PostFX
* 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 scanlines = 0.0F; // Intensidad de las scanlines
float chroma = 0.0F; // Aberración cromática
@@ -18,15 +18,15 @@ struct PostFXParams {
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
float curvature = 0.0F; // Curvatura barrel CRT
float bleeding = 0.0F; // Sangrado de color NTSC
};
};
/**
/**
* @brief Interfaz abstracta para backends de renderizado con shaders
*
* Esta interfaz define el contrato que todos los backends de shaders
* deben cumplir (OpenGL, Metal, Vulkan, etc.)
*/
class ShaderBackend {
class ShaderBackend {
public:
virtual ~ShaderBackend() = default;
@@ -87,6 +87,6 @@ class ShaderBackend {
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
*/
[[nodiscard]] virtual auto isHardwareAccelerated() const -> bool = 0;
};
};
} // namespace Rendering

View File

@@ -430,19 +430,30 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
// Hash 2D estable per a dithering sense flickering
static auto pixelThreshold(int col, int row) -> float {
auto h = static_cast<uint32_t>(col) * 2246822519U ^ static_cast<uint32_t>(row) * 2654435761U;
auto h = (static_cast<uint32_t>(col) * 2246822519U) ^ (static_cast<uint32_t>(row) * 2654435761U);
h ^= (h >> 13);
h *= 1274126177U;
h ^= (h >> 16);
return static_cast<float>(h & 0xFFFFU) / 65536.0F;
}
// Calcula la densidad de fade para un pixel en posición screen_y
static auto computeFadeDensity(int screen_y, int fade_h, int canvas_height) -> float {
if (screen_y < fade_h) {
return static_cast<float>(fade_h - screen_y) / static_cast<float>(fade_h);
}
if (screen_y >= canvas_height - fade_h) {
return static_cast<float>(screen_y - (canvas_height - fade_h)) / static_cast<float>(fade_h);
}
return 0.0F;
}
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect) {
const int SX = src_rect ? static_cast<int>(src_rect->x) : 0;
const int SY = src_rect ? static_cast<int>(src_rect->y) : 0;
const int SW = src_rect ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
const int SH = src_rect ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height);
const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0;
const int SY = (src_rect != nullptr) ? static_cast<int>(src_rect->y) : 0;
const int SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
const int SH = (src_rect != nullptr) ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height);
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
@@ -452,12 +463,7 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
continue;
}
float density = 0.0F;
if (SCREEN_Y < fade_h) {
density = static_cast<float>(fade_h - SCREEN_Y) / static_cast<float>(fade_h);
} else if (SCREEN_Y >= canvas_height - fade_h) {
density = static_cast<float>(SCREEN_Y - (canvas_height - fade_h)) / static_cast<float>(fade_h);
}
const float DENSITY = computeFadeDensity(SCREEN_Y, fade_h, canvas_height);
for (int col = 0; col < SW; col++) {
const int SCREEN_X = x + col;
@@ -465,12 +471,12 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
continue;
}
const Uint8 COLOR = surface_data_->data[(SY + row) * static_cast<int>(surface_data_->width) + (SX + col)];
const Uint8 COLOR = surface_data_->data[((SY + row) * static_cast<int>(surface_data_->width)) + (SX + col)];
if (static_cast<int>(COLOR) == transparent_color_) {
continue;
}
if (pixelThreshold(col, row) < density) {
if (pixelThreshold(col, row) < DENSITY) {
continue; // Pixel tapat per la zona de fade
}
@@ -481,10 +487,10 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
// Idem però reemplaçant un color índex
void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect) {
const int SX = src_rect ? static_cast<int>(src_rect->x) : 0;
const int SY = src_rect ? static_cast<int>(src_rect->y) : 0;
const int SW = src_rect ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
const int SH = src_rect ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height);
const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0;
const int SY = (src_rect != nullptr) ? static_cast<int>(src_rect->y) : 0;
const int SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
const int SH = (src_rect != nullptr) ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height);
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
@@ -494,12 +500,7 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
continue;
}
float density = 0.0F;
if (SCREEN_Y < fade_h) {
density = static_cast<float>(fade_h - SCREEN_Y) / static_cast<float>(fade_h);
} else if (SCREEN_Y >= canvas_height - fade_h) {
density = static_cast<float>(SCREEN_Y - (canvas_height - fade_h)) / static_cast<float>(fade_h);
}
const float DENSITY = computeFadeDensity(SCREEN_Y, fade_h, canvas_height);
for (int col = 0; col < SW; col++) {
const int SCREEN_X = x + col;
@@ -507,12 +508,12 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
continue;
}
const Uint8 COLOR = surface_data_->data[(SY + row) * static_cast<int>(surface_data_->width) + (SX + col)];
const Uint8 COLOR = surface_data_->data[((SY + row) * static_cast<int>(surface_data_->width)) + (SX + col)];
if (static_cast<int>(COLOR) == transparent_color_) {
continue;
}
if (pixelThreshold(col, row) < density) {
if (pixelThreshold(col, row) < DENSITY) {
continue; // Pixel tapat per la zona de fade
}

View File

@@ -219,7 +219,7 @@ SurfaceAnimatedSprite::SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, S
: SurfaceMovingSprite(std::move(surface), pos) {
// animations_ queda buit (protegit per el guard de animate())
if (surface_) {
clip_ = {0, 0, static_cast<float>(surface_->getWidth()), static_cast<float>(surface_->getHeight())};
clip_ = {.x = 0, .y = 0, .w = surface_->getWidth(), .h = surface_->getHeight()};
}
}
@@ -239,7 +239,7 @@ auto SurfaceAnimatedSprite::getIndex(const std::string& name) -> int {
// Calcula el frame correspondiente a la animación (time-based)
void SurfaceAnimatedSprite::animate(float delta_time) {
if (animations_.empty()) return;
if (animations_.empty()) { return; }
if (animations_[current_animation_].speed <= 0.0F) {
return;
}

View File

@@ -7,7 +7,7 @@
// Hash 2D estable per a dithering (rank aleatori per posició de píxel)
static auto pixelRank(int col, int row) -> float {
auto h = static_cast<uint32_t>(col) * 2246822519U ^ static_cast<uint32_t>(row) * 2654435761U;
auto h = (static_cast<uint32_t>(col) * 2246822519U) ^ (static_cast<uint32_t>(row) * 2654435761U);
h ^= (h >> 13);
h *= 1274126177U;
h ^= (h >> 16);
@@ -28,7 +28,7 @@ auto SurfaceDissolveSprite::computePixelRank(int col, int row, int frame_h, Diss
y_factor = static_cast<float>(frame_h - 1 - row) / static_cast<float>(frame_h);
}
return y_factor * 0.7F + RANDOM * 0.3F;
return (y_factor * 0.7F) + (RANDOM * 0.3F);
}
// Constructor per a surface directa (sense AnimationResource)
@@ -92,14 +92,14 @@ void SurfaceDissolveSprite::rebuildDisplaySurface() {
// Copia píxels filtrats per progress_
for (int row = 0; row < SH; ++row) {
for (int col = 0; col < SW; ++col) {
const Uint8 COLOR = src_data->data[(SY + row) * SRC_W + (SX + col)];
const Uint8 COLOR = src_data->data[((SY + row) * SRC_W) + (SX + col)];
if (COLOR == TRANSPARENT) {
continue;
}
const float RANK = computePixelRank(col, row, SH, direction_);
if (RANK >= progress_) {
const Uint8 OUT = (COLOR == source_color_) ? target_color_ : COLOR;
dst_data->data[(SY + row) * DST_W + (SX + col)] = OUT;
dst_data->data[((SY + row) * DST_W) + (SX + col)] = OUT;
}
}
}

View File

@@ -24,26 +24,26 @@ struct JA_Sound_t; // lines 18-18
namespace Resource {
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Cache* Cache::cache = nullptr;
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Cache* Cache::cache = nullptr;
// [SINGLETON] Crearemos el objeto cache con esta función estática
void Cache::init() { Cache::cache = new Cache(); }
// [SINGLETON] Crearemos el objeto cache con esta función estática
void Cache::init() { Cache::cache = new Cache(); }
// [SINGLETON] Destruiremos el objeto cache con esta función estática
void Cache::destroy() { delete Cache::cache; }
// [SINGLETON] Destruiremos el objeto cache con esta función estática
void Cache::destroy() { delete Cache::cache; }
// [SINGLETON] Con este método obtenemos el objeto cache y podemos trabajar con él
auto Cache::get() -> Cache* { return Cache::cache; }
// [SINGLETON] Con este método obtenemos el objeto cache y podemos trabajar con él
auto Cache::get() -> Cache* { return Cache::cache; }
// Constructor
Cache::Cache()
// Constructor
Cache::Cache()
: loading_text_(Screen::get()->getText()) {
load();
}
}
// Vacia todos los vectores de recursos
void Cache::clear() {
// Vacia todos los vectores de recursos
void Cache::clear() {
clearSounds();
clearMusics();
surfaces_.clear();
@@ -51,10 +51,10 @@ void Cache::clear() {
text_files_.clear();
texts_.clear();
animations_.clear();
}
}
// Carga todos los recursos
void Cache::load() {
// Carga todos los recursos
void Cache::load() {
calculateTotal();
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
std::cout << "\n** LOADING RESOURCES" << '\n';
@@ -67,16 +67,16 @@ void Cache::load() {
loadRooms();
createText();
std::cout << "\n** RESOURCES LOADED" << '\n';
}
}
// Recarga todos los recursos
void Cache::reload() {
// 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* {
// 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()) {
@@ -85,10 +85,10 @@ auto Cache::getSound(const std::string& name) -> JA_Sound_t* {
std::cerr << "Error: Sonido no encontrado " << name << '\n';
throw std::runtime_error("Sonido no encontrado: " + name);
}
}
// Obtiene la música a partir de un nombre
auto Cache::getMusic(const std::string& name) -> JA_Music_t* {
// Obtiene la música a partir de un nombre
auto Cache::getMusic(const std::string& name) -> JA_Music_t* {
auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; });
if (it != musics_.end()) {
@@ -97,10 +97,10 @@ auto Cache::getMusic(const std::string& name) -> JA_Music_t* {
std::cerr << "Error: Música no encontrada " << name << '\n';
throw std::runtime_error("Música no encontrada: " + name);
}
}
// Obtiene la surface a partir de un nombre
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
// Obtiene la surface a partir de un nombre
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) { return t.name == name; });
if (it != surfaces_.end()) {
@@ -109,10 +109,10 @@ auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> {
std::cerr << "Error: Imagen no encontrada " << name << '\n';
throw std::runtime_error("Imagen no encontrada: " + name);
}
}
// Obtiene la paleta a partir de un nombre
auto Cache::getPalette(const std::string& name) -> Palette {
// 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()) {
@@ -121,10 +121,10 @@ auto Cache::getPalette(const std::string& name) -> 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> {
// 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()) {
@@ -133,10 +133,10 @@ auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<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> {
// 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()) {
@@ -145,10 +145,10 @@ auto Cache::getText(const std::string& name) -> std::shared_ptr<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& {
// 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()) {
@@ -157,10 +157,10 @@ auto Cache::getAnimationData(const std::string& name) -> const AnimationResource
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> {
// 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()) {
@@ -169,24 +169,24 @@ auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> {
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>& {
// 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) {
// 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() {
// Carga los sonidos
void Cache::loadSounds() {
std::cout << "\n>> SOUND FILES" << '\n';
auto list = List::get()->getListByType(List::Type::SOUND);
sounds_.clear();
@@ -218,10 +218,10 @@ void Cache::loadSounds() {
throwLoadError("SOUND", l, e);
}
}
}
}
// Carga las musicas
void Cache::loadMusics() {
// Carga las musicas
void Cache::loadMusics() {
std::cout << "\n>> MUSIC FILES" << '\n';
auto list = List::get()->getListByType(List::Type::MUSIC);
musics_.clear();
@@ -253,10 +253,10 @@ void Cache::loadMusics() {
throwLoadError("MUSIC", l, e);
}
}
}
}
// Carga las texturas
void Cache::loadSurfaces() {
// Carga las texturas
void Cache::loadSurfaces() {
std::cout << "\n>> SURFACES" << '\n';
auto list = List::get()->getListByType(List::Type::BITMAP);
surfaces_.clear();
@@ -280,10 +280,10 @@ void Cache::loadSurfaces() {
getSurface("ending4.gif")->setTransparentColor();
getSurface("ending5.gif")->setTransparentColor();
getSurface("standard.gif")->setTransparentColor(16);
}
}
// Carga las paletas
void Cache::loadPalettes() {
// Carga las paletas
void Cache::loadPalettes() {
std::cout << "\n>> PALETTES" << '\n';
auto list = List::get()->getListByType(List::Type::PALETTE);
palettes_.clear();
@@ -297,10 +297,10 @@ void Cache::loadPalettes() {
throwLoadError("PALETTE", l, e);
}
}
}
}
// Carga los ficheros de texto
void Cache::loadTextFiles() {
// Carga los ficheros de texto
void Cache::loadTextFiles() {
std::cout << "\n>> TEXT FILES" << '\n';
auto list = List::get()->getListByType(List::Type::FONT);
text_files_.clear();
@@ -314,10 +314,10 @@ void Cache::loadTextFiles() {
throwLoadError("FONT", l, e);
}
}
}
}
// Carga las animaciones
void Cache::loadAnimations() {
// Carga las animaciones
void Cache::loadAnimations() {
std::cout << "\n>> ANIMATIONS" << '\n';
auto list = List::get()->getListByType(List::Type::ANIMATION);
animations_.clear();
@@ -340,10 +340,10 @@ void Cache::loadAnimations() {
throwLoadError("ANIMATION", l, e);
}
}
}
}
// Carga las habitaciones desde archivos YAML
void Cache::loadRooms() {
// Carga las habitaciones desde archivos YAML
void Cache::loadRooms() {
std::cout << "\n>> ROOMS" << '\n';
auto list = List::get()->getListByType(List::Type::ROOM);
rooms_.clear();
@@ -358,9 +358,9 @@ void Cache::loadRooms() {
throwLoadError("ROOM", l, e);
}
}
}
}
void Cache::createText() {
void Cache::createText() {
struct ResourceInfo {
std::string key; // Identificador del recurso
std::string texture_file; // Nombre del archivo de textura
@@ -380,10 +380,10 @@ void Cache::createText() {
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 ]");
}
}
}
// Vacía el vector de sonidos
void Cache::clearSounds() {
// 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) {
@@ -392,10 +392,10 @@ void Cache::clearSounds() {
}
}
sounds_.clear(); // Limpia el vector después de liberar todos los recursos
}
}
// Vacía el vector de musicas
void Cache::clearMusics() {
// 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) {
@@ -404,10 +404,10 @@ void Cache::clearMusics() {
}
}
musics_.clear(); // Limpia el vector después de liberar todos los recursos
}
}
// Calcula el numero de recursos para cargar
void Cache::calculateTotal() {
// Calcula el numero de recursos para cargar
void Cache::calculateTotal() {
std::vector<List::Type> asset_types = {
List::Type::SOUND,
List::Type::MUSIC,
@@ -424,10 +424,10 @@ void Cache::calculateTotal() {
}
count_ = ResourceCount{.total = total, .loaded = 0};
}
}
// Muestra el progreso de carga
void Cache::renderProgress() {
// Muestra el progreso de carga
void Cache::renderProgress() {
constexpr float X_PADDING = 60.0F;
constexpr float Y_PADDING = 10.0F;
constexpr float BAR_HEIGHT = 5.0F;
@@ -470,10 +470,10 @@ void Cache::renderProgress() {
surface->fillRect(&rect_full, BAR_COLOR);
Screen::get()->render();
}
}
// Comprueba los eventos de la pantalla de carga
void Cache::checkEvents() {
// Comprueba los eventos de la pantalla de carga
void Cache::checkEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
@@ -487,15 +487,15 @@ void Cache::checkEvents() {
break;
}
}
}
}
// Actualiza el progreso de carga
void Cache::updateLoadingProgress(int steps) {
// Actualiza el progreso de carga
void Cache::updateLoadingProgress(int steps) {
count_.add(1);
if (count_.loaded % steps == 0 || count_.loaded == count_.total) {
renderProgress();
}
checkEvents();
}
}
} // namespace Resource

View File

@@ -9,7 +9,7 @@
namespace Resource {
class Cache {
class Cache {
public:
static void init(); // Inicialización singleton
static void destroy(); // Destrucción singleton
@@ -88,6 +88,6 @@ class Cache {
ResourceCount count_{}; // Contador de recursos
std::shared_ptr<Text> loading_text_; // Texto para la pantalla de carga
};
};
} // namespace Resource

View File

@@ -12,10 +12,10 @@
namespace Resource::Helper {
static bool resource_system_initialized = false;
static bool resource_system_initialized = false;
// Initialize the resource system
auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback)
// Initialize the resource system
auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback)
-> bool {
if (resource_system_initialized) {
std::cout << "ResourceHelper: Already initialized\n";
@@ -35,19 +35,19 @@ auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback
}
return success;
}
}
// Shutdown the resource system
void shutdownResourceSystem() {
// 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> {
// 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
@@ -80,10 +80,10 @@ auto loadFile(const std::string& filepath) -> std::vector<uint8_t> {
// Load from filesystem
return Loader::get().loadResource(filepath);
}
}
// Check if a file exists
auto fileExists(const std::string& filepath) -> bool {
// Check if a file exists
auto fileExists(const std::string& filepath) -> bool {
if (!resource_system_initialized) {
return std::filesystem::exists(filepath);
}
@@ -98,10 +98,10 @@ auto fileExists(const std::string& filepath) -> bool {
// Check filesystem
return std::filesystem::exists(filepath);
}
}
// Convert asset path to pack path
auto getPackPath(const std::string& asset_path) -> std::string {
// 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
@@ -142,10 +142,10 @@ auto getPackPath(const std::string& asset_path) -> std::string {
}
return path;
}
}
// Check if file should use resource pack
auto shouldUseResourcePack(const std::string& filepath) -> bool {
// Check if file should use resource pack
auto shouldUseResourcePack(const std::string& filepath) -> bool {
std::string path = filepath;
std::ranges::replace(path, '\\', '/');
@@ -169,14 +169,14 @@ auto shouldUseResourcePack(const std::string& filepath) -> bool {
}
return false;
}
}
// Check if pack is loaded
auto isPackLoaded() -> bool {
// Check if pack is loaded
auto isPackLoaded() -> bool {
if (!resource_system_initialized) {
return false;
}
return Loader::get().isPackLoaded();
}
}
} // namespace Resource::Helper

View File

@@ -9,30 +9,30 @@
namespace Resource::Helper {
// Initialize the resource system
// pack_file: Path to resources.pack
// enable_fallback: Allow loading from filesystem if pack not available
auto initializeResourceSystem(const std::string& pack_file = "resources.pack",
// Initialize the resource system
// pack_file: Path to resources.pack
// enable_fallback: Allow loading from filesystem if pack not available
auto initializeResourceSystem(const std::string& pack_file = "resources.pack",
bool enable_fallback = true) -> bool;
// Shutdown the resource system
void shutdownResourceSystem();
// Shutdown the resource system
void shutdownResourceSystem();
// Load a file (tries pack first, then filesystem if fallback enabled)
auto loadFile(const std::string& filepath) -> std::vector<uint8_t>;
// Load a file (tries pack first, then filesystem if fallback enabled)
auto loadFile(const std::string& filepath) -> std::vector<uint8_t>;
// Check if a file exists
auto fileExists(const std::string& filepath) -> bool;
// Check if a file exists
auto fileExists(const std::string& filepath) -> bool;
// Convert an asset path to a pack path
// Example: "data/music/title.ogg" -> "music/title.ogg"
auto getPackPath(const std::string& asset_path) -> std::string;
// Convert an asset path to a pack path
// Example: "data/music/title.ogg" -> "music/title.ogg"
auto getPackPath(const std::string& asset_path) -> std::string;
// Check if a file should use the resource pack
// Returns false for config/ files (always from filesystem)
auto shouldUseResourcePack(const std::string& filepath) -> bool;
// Check if a file should use the resource pack
// Returns false for config/ files (always from filesystem)
auto shouldUseResourcePack(const std::string& filepath) -> bool;
// Check if pack is loaded
auto isPackLoaded() -> bool;
// Check if pack is loaded
auto isPackLoaded() -> bool;
} // namespace Resource::Helper

View File

@@ -16,23 +16,23 @@
namespace Resource {
// Singleton
List* List::instance = nullptr;
// Singleton
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);
}
}
void List::destroy() {
void List::destroy() {
delete List::instance;
}
}
auto List::get() -> List* {
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) {
// 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);
@@ -44,15 +44,15 @@ void List::addToMap(const std::string& file_path, Type type, bool required, bool
}
file_list_.emplace(filename, Item{std::move(full_path), type, required});
}
}
// Añade un elemento a la lista
void List::add(const std::string& file_path, Type type, bool required, bool absolute) {
// 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) {
// 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,
@@ -68,10 +68,10 @@ void List::loadFromFile(const std::string& config_file_path, const std::string&
// Parse using loadFromString
loadFromString(buffer.str(), prefix, system_folder);
}
}
// Carga recursos desde un string de configuración (para release con pack)
void List::loadFromString(const std::string& config_content, const std::string& prefix, const std::string& system_folder) {
// Carga recursos desde un string de configuración (para release con pack)
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);
@@ -153,10 +153,10 @@ void List::loadFromString(const std::string& config_content, const std::string&
"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 {
// 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;
@@ -164,10 +164,10 @@ auto List::get(const std::string& filename) const -> std::string {
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> {
// 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);
@@ -193,15 +193,15 @@ auto List::loadData(const std::string& filename) const -> std::vector<uint8_t> {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
return {};
}
}
// Verifica si un recurso existe
auto List::exists(const std::string& filename) const -> bool {
// Verifica si un recurso existe
auto List::exists(const std::string& filename) const -> bool {
return file_list_.find(filename) != file_list_.end();
}
}
// Parsea string a Type
auto List::parseAssetType(const std::string& type_str) -> Type {
// Parsea string a Type
auto List::parseAssetType(const std::string& type_str) -> Type {
if (type_str == "DATA") {
return Type::DATA;
}
@@ -232,10 +232,10 @@ auto List::parseAssetType(const std::string& type_str) -> Type {
}
throw std::runtime_error("Unknown asset type: " + type_str);
}
}
// Devuelve el nombre del tipo de recurso
auto List::getTypeName(Type type) -> std::string {
// Devuelve el nombre del tipo de recurso
auto List::getTypeName(Type type) -> std::string {
switch (type) {
case Type::DATA:
return "DATA";
@@ -256,10 +256,10 @@ auto List::getTypeName(Type type) -> std::string {
default:
return "ERROR";
}
}
}
// Devuelve la lista de recursos de un tipo
auto List::getListByType(Type type) const -> std::vector<std::string> {
// 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_) {
@@ -272,10 +272,10 @@ auto List::getListByType(Type type) const -> std::vector<std::string> {
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 {
// 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}
@@ -293,10 +293,10 @@ auto List::replaceVariables(const std::string& path, const std::string& prefix,
}
return result;
}
}
// Parsea las opciones de una línea de configuración
auto List::parseOptions(const std::string& options, bool& required, bool& absolute) -> void {
// 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;
}
@@ -315,6 +315,6 @@ auto List::parseOptions(const std::string& options, bool& required, bool& absolu
absolute = true;
}
}
}
}
} // namespace Resource

View File

@@ -8,8 +8,8 @@
namespace Resource {
// --- Clase List: gestor optimizado de recursos (singleton) ---
class List {
// --- Clase List: gestor optimizado de recursos (singleton) ---
class List {
public:
// --- Enums ---
enum class Type : int {
@@ -71,6 +71,6 @@ class List {
// --- Instancia singleton ---
static List* instance; // Instancia única de List
};
};
} // namespace Resource

View File

@@ -9,14 +9,14 @@
namespace Resource {
// Get singleton instance
auto Loader::get() -> Loader& {
// Get singleton instance
auto Loader::get() -> Loader& {
static Loader instance_;
return instance_;
}
}
// Initialize with a pack file
auto Loader::initialize(const std::string& pack_file, bool enable_fallback)
// Initialize with a pack file
auto Loader::initialize(const std::string& pack_file, bool enable_fallback)
-> bool {
if (initialized_) {
std::cout << "Loader: Already initialized\n";
@@ -50,10 +50,10 @@ auto Loader::initialize(const std::string& pack_file, bool enable_fallback)
std::cout << "Loader: Using filesystem fallback\n";
initialized_ = true;
return true;
}
}
// Load a resource
auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
// Load a resource
auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
if (!initialized_) {
std::cerr << "Loader: Not initialized\n";
return {};
@@ -78,10 +78,10 @@ auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
std::cerr << "Loader: Resource not found: " << filename << '\n';
return {};
}
}
// Check if a resource exists
auto Loader::resourceExists(const std::string& filename) -> bool {
// Check if a resource exists
auto Loader::resourceExists(const std::string& filename) -> bool {
if (!initialized_) {
return false;
}
@@ -99,30 +99,30 @@ auto Loader::resourceExists(const std::string& filename) -> bool {
}
return false;
}
}
// Check if pack is loaded
auto Loader::isPackLoaded() const -> bool {
// 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 {
// 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() {
// 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)
// 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) {
@@ -139,15 +139,15 @@ auto Loader::loadFromFilesystem(const std::string& filepath)
}
return data;
}
}
// Check if file exists on filesystem
auto Loader::fileExistsOnFilesystem(const std::string& filepath) -> bool {
// 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 {
// 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;
@@ -165,10 +165,10 @@ auto Loader::validatePack() const -> bool {
<< '\n';
std::cout << "Loader: Pack validation successful\n";
return true;
}
}
// Load assets.yaml from pack
auto Loader::loadAssetsConfig() const -> std::string {
// 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 "";
@@ -194,6 +194,6 @@ auto Loader::loadAssetsConfig() const -> std::string {
<< " bytes)\n";
return config_content;
}
}
} // namespace Resource

View File

@@ -11,8 +11,8 @@
namespace Resource {
// Singleton class for loading resources from pack or filesystem
class Loader {
// Singleton class for loading resources from pack or filesystem
class Loader {
public:
static auto get() -> Loader&; // Singleton instance access
@@ -43,6 +43,6 @@ class Loader {
std::unique_ptr<Pack> resource_pack_; // Member variables
bool fallback_to_files_{true};
bool initialized_{false};
};
};
} // namespace Resource

View File

@@ -12,32 +12,32 @@
namespace Resource {
// Calculate CRC32 checksum for data verification
auto Pack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t {
// Calculate CRC32 checksum for data verification
auto Pack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t {
uint32_t checksum = 0x12345678;
for (unsigned char byte : data) {
checksum = ((checksum << 5) + checksum) + byte;
}
return checksum;
}
}
// XOR encryption (symmetric - same function for encrypt/decrypt)
void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
// 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) {
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> {
// 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';
@@ -54,10 +54,10 @@ auto Pack::readFile(const std::string& filepath) -> std::vector<uint8_t> {
}
return data;
}
}
// Add a single file to the pack
auto Pack::addFile(const std::string& filepath, const std::string& pack_name)
// 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()) {
@@ -77,10 +77,10 @@ auto Pack::addFile(const std::string& filepath, const std::string& pack_name)
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,
// 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;
@@ -114,10 +114,10 @@ auto Pack::addDirectory(const std::string& dir_path,
}
return true;
}
}
// Save the pack to a file
auto Pack::savePack(const std::string& pack_file) -> bool {
// Save the pack to a file
auto Pack::savePack(const std::string& pack_file) -> bool {
std::ofstream file(pack_file, std::ios::binary);
if (!file) {
std::cerr << "ResourcePack: Failed to create pack file: " << pack_file << '\n';
@@ -159,10 +159,10 @@ auto Pack::savePack(const std::string& pack_file) -> bool {
std::cout << "Total size: " << data_size << " bytes\n";
return true;
}
}
// Load a pack from a file
auto Pack::loadPack(const std::string& pack_file) -> bool {
// Load a pack from a file
auto Pack::loadPack(const std::string& pack_file) -> bool {
std::ifstream file(pack_file, std::ios::binary);
if (!file) {
std::cerr << "ResourcePack: Failed to open pack file: " << pack_file << '\n';
@@ -226,10 +226,10 @@ auto Pack::loadPack(const std::string& pack_file) -> bool {
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> {
// 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 {};
@@ -255,15 +255,15 @@ auto Pack::getResource(const std::string& filename) -> std::vector<uint8_t> {
}
return result;
}
}
// Check if a resource exists
auto Pack::hasResource(const std::string& filename) const -> bool {
// 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> {
// 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_) {
@@ -271,10 +271,10 @@ auto Pack::getResourceList() const -> std::vector<std::string> {
}
std::ranges::sort(list);
return list;
}
}
// Calculate overall pack checksum for validation
auto Pack::calculatePackChecksum() const -> uint32_t {
// Calculate overall pack checksum for validation
auto Pack::calculatePackChecksum() const -> uint32_t {
if (!loaded_ || data_.empty()) {
return 0;
}
@@ -298,6 +298,6 @@ auto Pack::calculatePackChecksum() const -> uint32_t {
}
return global_checksum;
}
}
} // namespace Resource

View File

@@ -11,19 +11,19 @@
namespace Resource {
// Entry metadata for each resource in the pack
struct ResourceEntry {
// Entry metadata for each resource in the pack
struct ResourceEntry {
std::string filename; // Relative path within pack
uint64_t offset{0}; // Byte offset in data block
uint64_t size{0}; // Size in bytes
uint32_t checksum{0}; // CRC32 checksum for verification
};
};
// Resource pack file format
// Header: "JDDI" (4 bytes) + Version (4 bytes)
// Metadata: Count + array of ResourceEntry
// Data: Encrypted data block
class Pack {
// Resource pack file format
// Header: "JDDI" (4 bytes) + Version (4 bytes)
// Metadata: Count + array of ResourceEntry
// Data: Encrypted data block
class Pack {
public:
Pack() = default;
~Pack() = default;
@@ -63,6 +63,6 @@ class Pack {
std::unordered_map<std::string, ResourceEntry> resources_; // Member variables
std::vector<uint8_t> data_; // Encrypted data block
bool loaded_{false};
};
};
} // namespace Resource

View File

@@ -5,8 +5,8 @@
#include "game/scene_manager.hpp" // Para SceneManager
namespace GlobalEvents {
// Comprueba los eventos que se pueden producir en cualquier sección del juego
void handle(const SDL_Event& event) {
// Comprueba los eventos que se pueden producir en cualquier sección del juego
void handle(const SDL_Event& event) {
// Evento de salida de la aplicación
if (event.type == SDL_EVENT_QUIT) {
SceneManager::current = SceneManager::Scene::QUIT;
@@ -18,5 +18,5 @@ void handle(const SDL_Event& event) {
}
Mouse::handleEvent(event);
}
}
} // namespace GlobalEvents

View File

@@ -3,6 +3,6 @@
#include <SDL3/SDL.h>
namespace GlobalEvents {
// Comprueba los eventos que se pueden producir en cualquier sección del juego
void handle(const SDL_Event& event);
// Comprueba los eventos que se pueden producir en cualquier sección del juego
void handle(const SDL_Event& event);
} // namespace GlobalEvents

View File

@@ -8,116 +8,95 @@
// Forward declarations from Options namespace
namespace Options {
// enum class ControlScheme;
enum class NotificationPosition;
// enum class ControlScheme;
enum class NotificationPosition;
} // 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 ---
// Dimensiones del canvas del juego (usa GameCanvas como fuente única)
namespace Canvas {
constexpr int WIDTH = GameCanvas::WIDTH; // Ancho del canvas del juego (256)
constexpr int HEIGHT = GameCanvas::HEIGHT; // Alto del canvas del juego (192)
} // namespace Canvas
namespace Defaults::Window {
constexpr int ZOOM = 2; // Zoom de la ventana por defecto
} // namespace Defaults::Window
// --- WINDOW ---
namespace Window {
constexpr int ZOOM = 2; // Zoom de la ventana por defecto
} // namespace Window
namespace Defaults::Video {
constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana)
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
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 Video {
constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana)
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
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 Video
namespace Defaults::Border {
constexpr bool ENABLED = true; // Borde activado por defecto
constexpr int WIDTH = 32; // Ancho del borde por defecto
constexpr int HEIGHT = 24; // Alto del borde por defectoF
} // namespace Defaults::Border
// --- BORDER ---
namespace Border {
constexpr bool ENABLED = true; // Borde activado por defecto
constexpr int WIDTH = 32; // Ancho del borde por defecto
constexpr int HEIGHT = 24; // Alto del borde por defecto
} // namespace Border
namespace Defaults::Audio {
constexpr float VOLUME = 1.0F; // Volumen por defecto
constexpr bool ENABLED = true; // Audio por defecto
} // namespace Defaults::Audio
// --- AUDIO ---
namespace Audio {
constexpr float VOLUME = 1.0F; // Volumen por defecto
constexpr bool ENABLED = true; // Audio por defecto
} // namespace Audio
namespace Defaults::Music {
constexpr float VOLUME = 0.8F; // Volumen por defecto de la musica
constexpr bool ENABLED = true; // Musica habilitada por defecto
} // namespace Defaults::Music
// --- MUSIC ---
namespace Music {
constexpr float VOLUME = 0.8F; // Volumen por defecto de la musica
constexpr bool ENABLED = true; // Musica habilitada por defecto
} // namespace Music
namespace Defaults::Sound {
constexpr float VOLUME = 1.0F; // Volumen por defecto de los efectos de sonido
constexpr bool ENABLED = true; // Sonido habilitado por defecto
} // namespace Defaults::Sound
// --- SOUND ---
namespace Sound {
constexpr float VOLUME = 1.0F; // Volumen por defecto de los efectos de sonido
constexpr bool ENABLED = true; // Sonido habilitado por defecto
} // namespace Sound
namespace Defaults::Cheat {
constexpr bool INFINITE_LIVES = false; // Vidas infinitas desactivadas por defecto
constexpr bool INVINCIBLE = false; // Invencibilidad desactivada por defecto
constexpr bool JAIL_IS_OPEN = false; // Jail abierta desactivada por defecto
constexpr bool ALTERNATE_SKIN = false; // Skin alternativa desactivada por defecto
} // namespace Defaults::Cheat
// --- CHEATS ---
namespace Cheat {
constexpr bool INFINITE_LIVES = false; // Vidas infinitas desactivadas por defecto
constexpr bool INVINCIBLE = false; // Invencibilidad desactivada por defecto
constexpr bool JAIL_IS_OPEN = false; // Jail abierta desactivada por defecto
constexpr bool ALTERNATE_SKIN = false; // Skin alternativa desactivada por defecto
} // namespace Cheat
namespace Defaults::Stats {
constexpr int ROOMS = 0; // Habitaciones visitadas por defecto
constexpr int ITEMS = 0; // Items obtenidos por defecto
constexpr const char* WORST_NIGHTMARE = ""; // Habitación con más muertes por defecto
} // namespace Defaults::Stats
// --- STATS ---
namespace Stats {
constexpr int ROOMS = 0; // Habitaciones visitadas por defecto
constexpr int ITEMS = 0; // Items obtenidos por defecto
constexpr const char* WORST_NIGHTMARE = ""; // Habitación con más muertes por defecto
} // namespace Stats
namespace Defaults::Controls {
constexpr SDL_Scancode KEY_LEFT = SDL_SCANCODE_LEFT; // Tecla izquierda por defecto
constexpr SDL_Scancode KEY_RIGHT = SDL_SCANCODE_RIGHT; // Tecla derecha por defecto
constexpr SDL_Scancode KEY_JUMP = SDL_SCANCODE_UP; // Tecla salto por defecto
// --- CONTROLS ---
namespace Controls {
constexpr SDL_Scancode KEY_LEFT = SDL_SCANCODE_LEFT; // Tecla izquierda por defecto
constexpr SDL_Scancode KEY_RIGHT = SDL_SCANCODE_RIGHT; // Tecla derecha por defecto
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
constexpr int GAMEPAD_BUTTON_RIGHT = SDL_GAMEPAD_BUTTON_DPAD_RIGHT; // Botón derecha por defecto
constexpr int GAMEPAD_BUTTON_JUMP = SDL_GAMEPAD_BUTTON_WEST; // Botón salto por defecto
} // namespace Defaults::Controls
constexpr int GAMEPAD_BUTTON_LEFT = SDL_GAMEPAD_BUTTON_DPAD_LEFT; // Botón izquierda por defecto
constexpr int GAMEPAD_BUTTON_RIGHT = SDL_GAMEPAD_BUTTON_DPAD_RIGHT; // Botón derecha por defecto
constexpr int GAMEPAD_BUTTON_JUMP = SDL_GAMEPAD_BUTTON_WEST; // Botón salto por defecto
} // namespace Controls
namespace Defaults::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 Defaults::Kiosk
// --- KIOSK ---
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 {
namespace Defaults::Game::Room {
#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
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
} // namespace Room
} // namespace Defaults::Game::Room
namespace Player {
namespace Defaults::Game::Player {
#ifdef _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 SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación 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 SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en debug
#else
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 SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación 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 SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial en release
#endif
} // namespace Player
} // namespace Game
} // namespace Defaults
} // namespace Defaults::Game::Player

View File

@@ -908,11 +908,7 @@ auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect
// Marca al jugador como muerto
void Player::markAsDead() {
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
is_alive_ = true; // No puede morir
} else {
is_alive_ = false; // Muere
}
is_alive_ = (Options::cheats.invincible == Options::Cheat::State::ENABLED);
}
#ifdef _DEBUG

View File

@@ -29,9 +29,9 @@ void CollisionMap::initializeSurfaces() {
// Devuelve el tipo de tile que hay en ese pixel
auto CollisionMap::getTile(SDL_FPoint point) const -> Tile {
const int row = static_cast<int>(point.y / TILE_SIZE);
const int col = static_cast<int>(point.x / TILE_SIZE);
const int POS = row * MAP_WIDTH + col;
const int ROW = static_cast<int>(point.y / TILE_SIZE);
const int COL = static_cast<int>(point.x / TILE_SIZE);
const int POS = (ROW * MAP_WIDTH) + COL;
return getTile(POS);
}

View File

@@ -13,19 +13,19 @@
namespace Options {
// --- Funciones helper de conversión ---
// --- Funciones helper de conversión ---
// Mapa de nombres de filtro
const std::unordered_map<Screen::Filter, std::string> FILTER_TO_STRING = {
// Mapa de nombres de filtro
const std::unordered_map<Screen::Filter, std::string> FILTER_TO_STRING = {
{Screen::Filter::NEAREST, "nearest"},
{Screen::Filter::LINEAR, "linear"}};
const std::unordered_map<std::string, Screen::Filter> STRING_TO_FILTER = {
const std::unordered_map<std::string, Screen::Filter> STRING_TO_FILTER = {
{"nearest", Screen::Filter::NEAREST},
{"linear", Screen::Filter::LINEAR}};
// Mapa de scancodes comunes (los más usados para controles de juego)
const std::unordered_map<SDL_Scancode, std::string> SCANCODE_TO_STRING = {
// Mapa de scancodes comunes (los más usados para controles de juego)
const std::unordered_map<SDL_Scancode, std::string> SCANCODE_TO_STRING = {
// Flechas
{SDL_SCANCODE_LEFT, "LEFT"},
{SDL_SCANCODE_RIGHT, "RIGHT"},
@@ -82,7 +82,7 @@ const std::unordered_map<SDL_Scancode, std::string> SCANCODE_TO_STRING = {
{SDL_SCANCODE_LALT, "LALT"},
{SDL_SCANCODE_RALT, "RALT"}};
const std::unordered_map<std::string, SDL_Scancode> STRING_TO_SCANCODE = {
const std::unordered_map<std::string, SDL_Scancode> STRING_TO_SCANCODE = {
// Flechas
{"LEFT", SDL_SCANCODE_LEFT},
{"RIGHT", SDL_SCANCODE_RIGHT},
@@ -139,8 +139,8 @@ const std::unordered_map<std::string, SDL_Scancode> STRING_TO_SCANCODE = {
{"LALT", SDL_SCANCODE_LALT},
{"RALT", SDL_SCANCODE_RALT}};
// Mapa extendido de botones de gamepad (incluye ejes como botones)
const std::unordered_map<int, std::string> GAMEPAD_BUTTON_TO_STRING = {
// Mapa extendido de botones de gamepad (incluye ejes como botones)
const std::unordered_map<int, std::string> GAMEPAD_BUTTON_TO_STRING = {
{SDL_GAMEPAD_BUTTON_WEST, "WEST"},
{SDL_GAMEPAD_BUTTON_NORTH, "NORTH"},
{SDL_GAMEPAD_BUTTON_EAST, "EAST"},
@@ -158,7 +158,7 @@ const std::unordered_map<int, std::string> GAMEPAD_BUTTON_TO_STRING = {
{200, "LEFT_STICK_LEFT"},
{201, "LEFT_STICK_RIGHT"}};
const std::unordered_map<std::string, int> STRING_TO_GAMEPAD_BUTTON = {
const std::unordered_map<std::string, int> STRING_TO_GAMEPAD_BUTTON = {
{"WEST", SDL_GAMEPAD_BUTTON_WEST},
{"NORTH", SDL_GAMEPAD_BUTTON_NORTH},
{"EAST", SDL_GAMEPAD_BUTTON_EAST},
@@ -176,8 +176,8 @@ const std::unordered_map<std::string, int> STRING_TO_GAMEPAD_BUTTON = {
{"LEFT_STICK_LEFT", 200},
{"LEFT_STICK_RIGHT", 201}};
// Lista de paletas válidas
const std::vector<std::string> VALID_PALETTES = {
// Lista de paletas válidas
const std::vector<std::string> VALID_PALETTES = {
"black-and-white",
"green-phosphor",
"island-joy-16",
@@ -194,33 +194,33 @@ const std::vector<std::string> VALID_PALETTES = {
"zx-spectrum-adjusted",
"zxarne-5-2"};
// Funciones helper de conversión
auto filterToString(Screen::Filter filter) -> std::string {
// Funciones helper de conversión
auto filterToString(Screen::Filter filter) -> std::string {
auto it = FILTER_TO_STRING.find(filter);
if (it != FILTER_TO_STRING.end()) {
return it->second;
}
return "nearest";
}
}
auto stringToFilter(const std::string& str) -> Screen::Filter {
auto stringToFilter(const std::string& str) -> Screen::Filter {
auto it = STRING_TO_FILTER.find(str);
if (it != STRING_TO_FILTER.end()) {
return it->second;
}
return Defaults::Video::FILTER;
}
}
auto scancodeToString(SDL_Scancode scancode) -> std::string {
auto scancodeToString(SDL_Scancode scancode) -> std::string {
auto it = SCANCODE_TO_STRING.find(scancode);
if (it != SCANCODE_TO_STRING.end()) {
return it->second;
}
// Fallback: devolver el código numérico como string
return std::to_string(static_cast<int>(scancode));
}
}
auto stringToScancode(const std::string& str, SDL_Scancode default_value) -> SDL_Scancode {
auto stringToScancode(const std::string& str, SDL_Scancode default_value) -> SDL_Scancode {
auto it = STRING_TO_SCANCODE.find(str);
if (it != STRING_TO_SCANCODE.end()) {
return it->second;
@@ -232,18 +232,18 @@ auto stringToScancode(const std::string& str, SDL_Scancode default_value) -> SDL
} catch (...) {
return default_value;
}
}
}
auto gamepadButtonToString(int button) -> std::string {
auto gamepadButtonToString(int button) -> std::string {
auto it = GAMEPAD_BUTTON_TO_STRING.find(button);
if (it != GAMEPAD_BUTTON_TO_STRING.end()) {
return it->second;
}
// Fallback: devolver el código numérico como string
return std::to_string(button);
}
}
auto stringToGamepadButton(const std::string& str, int default_value) -> int {
auto stringToGamepadButton(const std::string& str, int default_value) -> int {
auto it = STRING_TO_GAMEPAD_BUTTON.find(str);
if (it != STRING_TO_GAMEPAD_BUTTON.end()) {
return it->second;
@@ -254,18 +254,18 @@ auto stringToGamepadButton(const std::string& str, int default_value) -> int {
} catch (...) {
return default_value;
}
}
}
auto isValidPalette(const std::string& palette) -> bool {
auto isValidPalette(const std::string& palette) -> bool {
std::string lower_palette = palette;
std::ranges::transform(lower_palette, lower_palette.begin(), ::tolower);
return std::ranges::any_of(VALID_PALETTES, [&lower_palette](const auto& valid) { return valid == lower_palette; });
}
}
// --- Funciones helper para loadFromFile() ---
// --- Funciones helper para loadFromFile() ---
// Carga configuración de ventana desde YAML
void loadWindowConfigFromYaml(const fkyaml::node& yaml) {
// Carga configuración de ventana desde YAML
void loadWindowConfigFromYaml(const fkyaml::node& yaml) {
if (yaml.contains("window")) {
const auto& win = yaml["window"];
if (win.contains("zoom")) {
@@ -277,10 +277,10 @@ void loadWindowConfigFromYaml(const fkyaml::node& yaml) {
}
}
}
}
}
// Carga configuración de borde desde YAML
void loadBorderConfigFromYaml(const fkyaml::node& border) {
// Carga configuración de borde desde YAML
void loadBorderConfigFromYaml(const fkyaml::node& border) {
if (border.contains("enabled")) {
try {
video.border.enabled = border["enabled"].get_value<bool>();
@@ -306,10 +306,10 @@ void loadBorderConfigFromYaml(const fkyaml::node& border) {
video.border.height = Defaults::Border::HEIGHT;
}
}
}
}
// Carga los campos básicos de configuración de video
void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) {
// Carga los campos básicos de configuración de video
void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) {
// fullscreen (antes era "mode")
if (vid.contains("fullscreen")) {
try {
@@ -373,10 +373,10 @@ void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) {
video.palette = Defaults::Video::PALETTE_NAME;
}
}
}
}
// Carga configuración de video desde YAML
void loadVideoConfigFromYaml(const fkyaml::node& yaml) {
// Carga configuración de video desde YAML
void loadVideoConfigFromYaml(const fkyaml::node& yaml) {
if (yaml.contains("video")) {
const auto& vid = yaml["video"];
loadBasicVideoFieldsFromYaml(vid);
@@ -386,10 +386,10 @@ void loadVideoConfigFromYaml(const fkyaml::node& yaml) {
loadBorderConfigFromYaml(vid["border"]);
}
}
}
}
// Carga controles de teclado desde YAML
void loadKeyboardControlsFromYaml(const fkyaml::node& yaml) {
// Carga controles de teclado desde YAML
void loadKeyboardControlsFromYaml(const fkyaml::node& yaml) {
if (yaml.contains("keyboard_controls")) {
const auto& ctrl = yaml["keyboard_controls"];
@@ -420,10 +420,10 @@ void loadKeyboardControlsFromYaml(const fkyaml::node& yaml) {
}
}
}
}
}
// Carga controles de gamepad desde YAML
void loadGamepadControlsFromYaml(const fkyaml::node& yaml) {
// Carga controles de gamepad desde YAML
void loadGamepadControlsFromYaml(const fkyaml::node& yaml) {
if (yaml.contains("gamepad_controls")) {
const auto& gp = yaml["gamepad_controls"];
@@ -454,10 +454,10 @@ void loadGamepadControlsFromYaml(const fkyaml::node& yaml) {
}
}
}
}
}
// Carga configuración del modo kiosko desde YAML
void loadKioskConfigFromYaml(const fkyaml::node& yaml) {
// Carga configuración del modo kiosko desde YAML
void loadKioskConfigFromYaml(const fkyaml::node& yaml) {
if (yaml.contains("kiosk")) {
const auto& k = yaml["kiosk"];
@@ -485,24 +485,24 @@ void loadKioskConfigFromYaml(const fkyaml::node& yaml) {
}
}
}
}
}
// Crea e inicializa las opciones del programa
void init() {
// Crea e inicializa las opciones del programa
void init() {
#ifdef _DEBUG
console = true;
#else
console = false;
#endif
}
}
// Establece la ruta del fichero de configuración
void setConfigFile(const std::string& path) {
// Establece la ruta del fichero de configuración
void setConfigFile(const std::string& path) {
config_file_path = path;
}
}
// Carga las opciones desde el fichero configurado
auto loadFromFile() -> bool {
// Carga las opciones desde el fichero configurado
auto loadFromFile() -> bool {
// Versión esperada del fichero
const std::string CONFIG_VERSION = Texts::VERSION;
version = "";
@@ -566,10 +566,10 @@ auto loadFromFile() -> bool {
saveToFile();
return true;
}
}
}
// Guarda las opciones al fichero configurado
auto saveToFile() -> bool {
// Guarda las opciones al fichero configurado
auto saveToFile() -> bool {
// Abre el fichero para escritura
std::ofstream file(config_file_path);
if (!file.is_open()) {
@@ -647,15 +647,24 @@ auto saveToFile() -> bool {
}
return true;
}
}
// Establece la ruta del fichero de PostFX
void setPostFXFile(const std::string& path) {
// Establece la ruta del fichero de PostFX
void setPostFXFile(const std::string& path) {
postfx_file_path = path;
}
}
// Carga los presets de PostFX desde el fichero
auto loadPostFXFromFile() -> bool {
// Helper: extrae un campo float de un nodo YAML si existe, ignorando errores de conversión
static void parseFloatField(const fkyaml::node& node, const std::string& key, float& target) {
if (node.contains(key)) {
try {
target = node[key].get_value<float>();
} catch (...) {}
}
}
// Carga los presets de PostFX desde el fichero
auto loadPostFXFromFile() -> bool {
postfx_presets.clear();
current_postfx_preset = 0;
@@ -675,47 +684,18 @@ auto loadPostFXFromFile() -> bool {
if (yaml.contains("presets")) {
const auto& presets = yaml["presets"];
for (size_t i = 0; i < presets.size(); ++i) {
const auto& p = presets[i];
for (const auto& p : presets) {
PostFXPreset preset;
if (p.contains("name")) {
preset.name = p["name"].get_value<std::string>();
}
if (p.contains("vignette")) {
try {
preset.vignette = p["vignette"].get_value<float>();
} catch (...) {}
}
if (p.contains("scanlines")) {
try {
preset.scanlines = p["scanlines"].get_value<float>();
} catch (...) {}
}
if (p.contains("chroma")) {
try {
preset.chroma = p["chroma"].get_value<float>();
} catch (...) {}
}
if (p.contains("mask")) {
try {
preset.mask = p["mask"].get_value<float>();
} catch (...) {}
}
if (p.contains("gamma")) {
try {
preset.gamma = p["gamma"].get_value<float>();
} catch (...) {}
}
if (p.contains("curvature")) {
try {
preset.curvature = p["curvature"].get_value<float>();
} catch (...) {}
}
if (p.contains("bleeding")) {
try {
preset.bleeding = p["bleeding"].get_value<float>();
} catch (...) {}
}
parseFloatField(p, "vignette", preset.vignette);
parseFloatField(p, "scanlines", preset.scanlines);
parseFloatField(p, "chroma", preset.chroma);
parseFloatField(p, "mask", preset.mask);
parseFloatField(p, "gamma", preset.gamma);
parseFloatField(p, "curvature", preset.curvature);
parseFloatField(p, "bleeding", preset.bleeding);
postfx_presets.push_back(preset);
}
}
@@ -732,10 +712,10 @@ auto loadPostFXFromFile() -> bool {
}
return savePostFXToFile();
}
}
}
// Guarda los presets de PostFX por defecto
auto savePostFXToFile() -> bool {
// Guarda los presets de PostFX por defecto
auto savePostFXToFile() -> bool {
if (postfx_file_path.empty()) {
return false;
}
@@ -816,6 +796,6 @@ auto savePostFXToFile() -> bool {
current_postfx_preset = 0;
return true;
}
}
} // namespace Options

View File

@@ -15,22 +15,22 @@
// --- Namespace Options: gestión de configuración y opciones del juego ---
namespace Options {
// Estructura para las opciones de control de teclado
struct KeyboardControls {
// Estructura para las opciones de control de teclado
struct KeyboardControls {
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_jump{Defaults::Controls::KEY_JUMP}; // Tecla para saltar
};
};
// Estructura para las opciones de control del gamepad/joystick
struct GamepadControls {
// Estructura para las opciones de control del gamepad/joystick
struct GamepadControls {
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_jump{Defaults::Controls::GAMEPAD_BUTTON_JUMP}; // Botón para saltar (por defecto: WEST/X button)
};
};
// Estructura para albergar trucos
struct Cheat {
// Estructura para albergar trucos
struct Cheat {
enum class State : bool {
DISABLED = false,
ENABLED = true
@@ -45,38 +45,38 @@ struct Cheat {
[[nodiscard]] auto enabled() const -> bool {
return infinite_lives == State::ENABLED || invincible == State::ENABLED || jail_is_open == State::ENABLED;
}
};
};
// Estructura para almacenar estadísticas
struct Stats {
// Estructura para almacenar estadísticas
struct Stats {
int rooms{Defaults::Stats::ROOMS}; // Cantidad de habitaciones visitadas
int items{Defaults::Stats::ITEMS}; // Cantidad de items obtenidos
std::string worst_nightmare{Defaults::Stats::WORST_NIGHTMARE}; // Habitación con más muertes acumuladas
};
};
// Estructura para el modo kiosko
struct Kiosk {
// Estructura para el modo kiosko
struct Kiosk {
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
bool infinite_lives{Defaults::Kiosk::INFINITE_LIVES}; // Indica si el jugador tiene vidas infinitas en modo kiosko
};
};
// Estructura con opciones de la ventana
struct Window {
// Estructura con opciones de la ventana
struct Window {
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 max_zoom{Defaults::Window::ZOOM}; // Máximo tamaño de zoom para la ventana
};
};
// Estructura para gestionar el borde de la pantalla
struct Border {
// Estructura para gestionar el borde de la pantalla
struct Border {
bool enabled{Defaults::Border::ENABLED}; // Indica si se ha de mostrar el borde
float width{Defaults::Border::WIDTH}; // Ancho del borde
float height{Defaults::Border::HEIGHT}; // Alto del borde
};
};
// Estructura para las opciones de video
struct Video {
// Estructura para las opciones de video
struct Video {
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
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
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
};
};
// Estructura para las opciones de musica
struct Music {
// Estructura para las opciones de musica
struct Music {
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
};
};
// Estructura para las opciones de sonido
struct Sound {
// Estructura para las opciones de sonido
struct Sound {
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)
};
};
// Estructura para las opciones de audio
struct Audio {
// Estructura para las opciones de audio
struct Audio {
Music music{}; // Opciones para la música
Sound sound{}; // Opciones para los efectos de sonido
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)
};
};
// Estructura para las opciones de juego
struct Game {
// Estructura para las opciones de juego
struct Game {
float width{Defaults::Canvas::WIDTH}; // Ancho de la resolucion del juego
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
};
};
// Estructura para un preset de PostFX
struct PostFXPreset {
// Estructura para un preset de PostFX
struct PostFXPreset {
std::string name; // Nombre del preset
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)
@@ -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 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)
};
};
// --- Variables globales ---
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 Cheat cheats{}; // Contiene trucos y ventajas para el juego
inline Game game{}; // Opciones de juego
inline Video video{}; // Opciones de video
inline Stats stats{}; // Datos con las estadisticas de juego
inline Window window{}; // Opciones relativas a la ventana
inline Audio audio{}; // Opciones relativas al audio
inline KeyboardControls keyboard_controls{}; // Teclas usadas para jugar
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
inline Kiosk kiosk{}; // Opciones del modo kiosko
// --- Variables globales ---
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 Cheat cheats{}; // Contiene trucos y ventajas para el juego
inline Game game{}; // Opciones de juego
inline Video video{}; // Opciones de video
inline Stats stats{}; // Datos con las estadisticas de juego
inline Window window{}; // Opciones relativas a la ventana
inline Audio audio{}; // Opciones relativas al audio
inline KeyboardControls keyboard_controls{}; // Teclas usadas para jugar
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
inline Kiosk kiosk{}; // Opciones del modo kiosko
// Ruta completa del fichero de configuración (establecida mediante setConfigFile)
inline std::string config_file_path{};
// Ruta completa del fichero de configuración (establecida mediante setConfigFile)
inline std::string config_file_path{};
// --- Variables 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 std::string postfx_file_path{}; // Ruta del fichero postfx.yaml
// --- Variables 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 std::string postfx_file_path{}; // Ruta del fichero postfx.yaml
// --- Funciones públicas ---
void init(); // Crea e inicializa las opciones del programa
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 saveToFile() -> bool; // Guarda las opciones al fichero configurado
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 savePostFXToFile() -> bool; // Guarda los presets de PostFX por defecto
// --- Funciones públicas ---
void init(); // Crea e inicializa las opciones del programa
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 saveToFile() -> bool; // Guarda las opciones al fichero configurado
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 savePostFXToFile() -> bool; // Guarda los presets de PostFX por defecto
} // namespace Options

View File

@@ -9,8 +9,8 @@
namespace SceneManager {
// --- Escenas del programa ---
enum class Scene {
// --- Escenas del programa ---
enum class Scene {
LOGO, // Pantalla del logo
LOADING_SCREEN, // Pantalla de carga
TITLE, // Pantalla de título/menú principal
@@ -21,24 +21,24 @@ enum class Scene {
ENDING, // Final del juego (ending 1)
ENDING2, // Final del juego (ending 2)
QUIT // Salir del programa
};
};
// --- Opciones para transiciones entre escenas ---
enum class Options {
// --- Opciones para transiciones entre escenas ---
enum class Options {
NONE, // Sin opciones especiales
LOGO_TO_LOADING_SCREEN, // Del logo a la intro
LOGO_TO_TITLE, // Del logo al título
TITLE_WITH_LOADING_SCREEN, // Al título mostrando pantalla de carga
TITLE_WITHOUT_LOADING_SCREEN // Al título sin pantalla de carga
};
};
// --- Variables de estado globales ---
#ifdef _DEBUG
inline Scene current = Scene::GAME; // Escena actual
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
inline Scene current = Scene::GAME; // Escena actual
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
#else
inline Scene current = Scene::LOGO; // Escena actual
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
inline Scene current = Scene::LOGO; // Escena actual
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
#endif
} // namespace SceneManager

View File

@@ -111,6 +111,17 @@ void Ending::transitionToState(State new_state) {
}
}
// Lógica de fade común a los estados SCENE_N
void Ending::handleSceneFadeout(float scene_duration, float delta_time) {
if (state_time_ >= scene_duration - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
if (!scene_cover_) {
scene_cover_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true);
}
scene_cover_->update(fadeout_time_);
}
}
// Actualiza la máquina de estados
void Ending::updateState(float delta_time) {
state_time_ += delta_time;
@@ -125,57 +136,27 @@ void Ending::updateState(float delta_time) {
case State::SCENE_0:
checkChangeScene();
if (state_time_ >= SCENE_0_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
if (!scene_cover_) {
scene_cover_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true);
}
scene_cover_->update(fadeout_time_);
}
handleSceneFadeout(SCENE_0_DURATION, delta_time);
break;
case State::SCENE_1:
checkChangeScene();
if (state_time_ >= SCENE_1_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
if (!scene_cover_) {
scene_cover_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true);
}
scene_cover_->update(fadeout_time_);
}
handleSceneFadeout(SCENE_1_DURATION, delta_time);
break;
case State::SCENE_2:
checkChangeScene();
if (state_time_ >= SCENE_2_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
if (!scene_cover_) {
scene_cover_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true);
}
scene_cover_->update(fadeout_time_);
}
handleSceneFadeout(SCENE_2_DURATION, delta_time);
break;
case State::SCENE_3:
checkChangeScene();
if (state_time_ >= SCENE_3_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
if (!scene_cover_) {
scene_cover_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true);
}
scene_cover_->update(fadeout_time_);
}
handleSceneFadeout(SCENE_3_DURATION, delta_time);
break;
case State::SCENE_4:
checkChangeScene();
if (state_time_ >= SCENE_4_DURATION - FADEOUT_START_OFFSET) {
fadeout_time_ += delta_time;
if (!scene_cover_) {
scene_cover_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, COVER_PIXELS_PER_SECOND, STEP_DURATION, COVER_STEPS, true);
}
scene_cover_->update(fadeout_time_);
}
handleSceneFadeout(SCENE_4_DURATION, delta_time);
break;
case State::ENDING:

View File

@@ -83,6 +83,7 @@ class Ending {
void iniPics(); // Inicializa las imágenes
void iniScenes(); // Inicializa las escenas
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 transitionToState(State new_state); // Transición entre estados
void updateSpriteCovers(); // Actualiza las cortinillas de los elementos
void checkChangeScene(); // Comprueba si se ha de cambiar de escena

View File

@@ -285,7 +285,7 @@ void Ending2::updateSprites(float delta) {
const float Y = sprite->getPosY();
const float H = sprite->getHeight();
const float CANVAS_H = static_cast<float>(Options::game.height);
const auto CANVAS_H = Options::game.height;
// Checkpoint inferior: sprite entra per baix → generar de dalt a baix
if (Y > static_cast<float>(ENTRY_EXIT_PADDING) && Y <= CANVAS_H - H - ENTRY_EXIT_PADDING && sprite->getProgress() >= 1.0F && sprite->isTransitionDone()) {
@@ -306,7 +306,7 @@ void Ending2::updateTextSprites(float delta) {
const float Y = sprite->getPosY();
const float H = sprite->getHeight();
const float CANVAS_H = static_cast<float>(Options::game.height);
const auto CANVAS_H = Options::game.height;
if (Y > static_cast<float>(ENTRY_EXIT_PADDING) && Y <= CANVAS_H - H - ENTRY_EXIT_PADDING && sprite->getProgress() >= 1.0F && sprite->isTransitionDone()) {
sprite->startGenerate(TRANSITION_DURATION_MS, DissolveDirection::UP);
@@ -325,7 +325,7 @@ void Ending2::updateTexts(float delta) {
const float Y = sprite->getPosY();
const float H = sprite->getHeight();
const float CANVAS_H = static_cast<float>(Options::game.height);
const auto CANVAS_H = Options::game.height;
// Checkpoint inferior: text entra per baix → generar de dalt a baix
if (Y > static_cast<float>(ENTRY_EXIT_PADDING) && Y <= CANVAS_H - H - ENTRY_EXIT_PADDING && sprite->getProgress() >= 1.0F && sprite->isTransitionDone()) {

View File

@@ -366,6 +366,13 @@ void Game::renderPostFadeEnding() {
}
#ifdef _DEBUG
// Helper: alterna un cheat y muestra notificación con su estado
static void toggleCheat(Options::Cheat::State& cheat, const std::string& label) {
cheat = (cheat == Options::Cheat::State::ENABLED) ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED;
const bool ENABLED = (cheat == Options::Cheat::State::ENABLED);
Notifier::get()->show({label + (ENABLED ? " ENABLED" : " DISABLED")}, Notifier::Style::DEFAULT, -1, true);
}
// Pasa la información de debug
void Game::updateDebugInfo() {
// Debug::get()->add("X = " + std::to_string(static_cast<int>(player_->x_)) + ", Y = " + std::to_string(static_cast<int>(player_->y_)));
@@ -437,20 +444,17 @@ void Game::handleDebugEvents(const SDL_Event& event) {
break;
case SDLK_1:
Options::cheats.infinite_lives = Options::cheats.infinite_lives == Options::Cheat::State::ENABLED ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED;
Notifier::get()->show({std::string("INFINITE LIVES ") + (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED ? "ENABLED" : "DISABLED")}, Notifier::Style::DEFAULT, -1, true);
toggleCheat(Options::cheats.infinite_lives, "INFINITE LIVES");
player_->setColor();
break;
case SDLK_2:
Options::cheats.invincible = Options::cheats.invincible == Options::Cheat::State::ENABLED ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED;
Notifier::get()->show({std::string("INVINCIBLE ") + (Options::cheats.invincible == Options::Cheat::State::ENABLED ? "ENABLED" : "DISABLED")}, Notifier::Style::DEFAULT, -1, true);
toggleCheat(Options::cheats.invincible, "INVINCIBLE");
player_->setColor();
break;
case SDLK_3:
Options::cheats.jail_is_open = Options::cheats.jail_is_open == Options::Cheat::State::ENABLED ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED;
Notifier::get()->show({std::string("JAIL IS OPEN ") + (Options::cheats.jail_is_open == Options::Cheat::State::ENABLED ? "ENABLED" : "DISABLED")}, Notifier::Style::DEFAULT, -1, true);
toggleCheat(Options::cheats.jail_is_open, "JAIL IS OPEN");
break;
case SDLK_7:
@@ -506,7 +510,7 @@ void Game::handleDebugMouseDrag(float delta_time) {
// Calcular distancia al objetivo
float dx = game_x - player_x;
float dy = game_y - player_y;
float distance = std::sqrt(dx * dx + dy * dy);
float distance = std::sqrt((dx * dx) + (dy * dy));
// Constantes de velocidad con ease-in (aceleración progresiva)
constexpr float DRAG_SPEED_MIN = 30.0F; // Velocidad inicial (pixels/segundo)
@@ -517,13 +521,13 @@ void Game::handleDebugMouseDrag(float delta_time) {
if (!debug_dragging_player_) {
debug_drag_speed_ = DRAG_SPEED_MIN; // Iniciar con velocidad mínima
}
debug_drag_speed_ = std::min(DRAG_SPEED_MAX, debug_drag_speed_ + DRAG_ACCELERATION * delta_time);
debug_drag_speed_ = std::min(DRAG_SPEED_MAX, debug_drag_speed_ + (DRAG_ACCELERATION * delta_time));
if (distance > 1.0F) {
// Calcular el movimiento con la velocidad actual
float move_factor = std::min(1.0F, debug_drag_speed_ * delta_time / distance);
float new_x = player_x + dx * move_factor;
float new_y = player_y + dy * move_factor;
float new_x = player_x + (dx * move_factor);
float new_y = player_y + (dy * move_factor);
// Mover el jugador hacia la posición del cursor
player_->setDebugPosition(new_x, new_y);

View File

@@ -66,10 +66,10 @@ class Game {
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 renderPlaying(); // Renderiza el juego en estado PLAYING (directo a pantalla)
void renderBlackScreen(); // Renderiza el juego en estado BLACK_SCREEN (pantalla negra)
void renderGameOver(); // Renderiza el juego en estado GAME_OVER (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)
void renderFadeToEnding(); // Renderiza el juego en estado FADE_TO_ENDING (via backbuffer)
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
void handleInput(); // Comprueba el teclado
void checkPlayerIsOnBorder(); // Comprueba si el jugador esta en el borde de la pantalla y actua

View File

@@ -4,48 +4,48 @@
// Textos
namespace Texts {
constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner";
constexpr const char* COPYRIGHT = "@2022 JailDesigner";
constexpr const char* VERSION = "1.10"; // Versión por defecto
constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner";
constexpr const char* COPYRIGHT = "@2022 JailDesigner";
constexpr const char* VERSION = "1.10"; // Versión por defecto
} // namespace Texts
// Tamaño de bloque
namespace Tile {
constexpr int SIZE = 8;
constexpr int HALF_SIZE = SIZE / 2;
constexpr int SIZE = 8;
constexpr int HALF_SIZE = SIZE / 2;
} // namespace Tile
namespace PlayArea {
constexpr int TOP = (0 * Tile::SIZE);
constexpr int BOTTOM = (16 * Tile::SIZE);
constexpr int LEFT = (0 * Tile::SIZE);
constexpr int RIGHT = (32 * Tile::SIZE);
constexpr int WIDTH = RIGHT - LEFT;
constexpr int HEIGHT = BOTTOM - TOP;
constexpr int CENTER_X = LEFT + (WIDTH / 2);
constexpr int CENTER_FIRST_QUARTER_X = (WIDTH / 4);
constexpr int CENTER_THIRD_QUARTER_X = (WIDTH / 4) * 3;
constexpr int CENTER_Y = TOP + (HEIGHT / 2);
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
constexpr int TOP = (0 * Tile::SIZE);
constexpr int BOTTOM = (16 * Tile::SIZE);
constexpr int LEFT = (0 * Tile::SIZE);
constexpr int RIGHT = (32 * Tile::SIZE);
constexpr int WIDTH = RIGHT - LEFT;
constexpr int HEIGHT = BOTTOM - TOP;
constexpr int CENTER_X = LEFT + (WIDTH / 2);
constexpr int CENTER_FIRST_QUARTER_X = (WIDTH / 4);
constexpr int CENTER_THIRD_QUARTER_X = (WIDTH / 4) * 3;
constexpr int CENTER_Y = TOP + (HEIGHT / 2);
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
} // namespace PlayArea
namespace GameCanvas {
constexpr int WIDTH = 256;
constexpr int HEIGHT = 192;
constexpr int CENTER_X = WIDTH / 2;
constexpr int FIRST_QUARTER_X = WIDTH / 4;
constexpr int THIRD_QUARTER_X = (WIDTH / 4) * 3;
constexpr int CENTER_Y = HEIGHT / 2;
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
constexpr int WIDTH = 256;
constexpr int HEIGHT = 192;
constexpr int CENTER_X = WIDTH / 2;
constexpr int FIRST_QUARTER_X = WIDTH / 4;
constexpr int THIRD_QUARTER_X = (WIDTH / 4) * 3;
constexpr int CENTER_Y = HEIGHT / 2;
constexpr int FIRST_QUARTER_Y = HEIGHT / 4;
constexpr int THIRD_QUARTER_Y = (HEIGHT / 4) * 3;
} // namespace GameCanvas
namespace Collision {
constexpr int NONE = -1;
constexpr int NONE = -1;
} // namespace Collision
namespace Flip {
constexpr SDL_FlipMode LEFT = SDL_FLIP_HORIZONTAL;
constexpr SDL_FlipMode RIGHT = SDL_FLIP_NONE;
constexpr SDL_FlipMode LEFT = SDL_FLIP_HORIZONTAL;
constexpr SDL_FlipMode RIGHT = SDL_FLIP_NONE;
} // namespace Flip

View File

@@ -22,110 +22,110 @@
namespace Easing {
// LINEAR
inline auto linear(float t) -> float {
// LINEAR
inline auto linear(float t) -> float {
return t;
}
}
// QUAD (Cuadrática: t^2)
inline auto quadIn(float t) -> float {
// QUAD (Cuadrática: t^2)
inline auto quadIn(float t) -> float {
return t * t;
}
}
inline auto quadOut(float t) -> float {
inline auto quadOut(float t) -> float {
return t * (2.0F - t);
}
}
inline auto quadInOut(float t) -> float {
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 {
// CUBIC (Cúbica: t^3)
inline auto cubicIn(float t) -> float {
return t * t * t;
}
}
inline auto cubicOut(float t) -> float {
inline auto cubicOut(float t) -> float {
const float F = t - 1.0F;
return (F * F * F) + 1.0F;
}
}
inline auto cubicInOut(float t) -> float {
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 {
// QUART (Cuártica: t^4)
inline auto quartIn(float t) -> float {
return t * t * t * t;
}
}
inline auto quartOut(float t) -> float {
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 {
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 {
// QUINT (Quíntica: t^5)
inline auto quintIn(float t) -> float {
return t * t * t * t * t;
}
}
inline auto quintOut(float t) -> float {
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 {
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 {
// 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 {
inline auto sineOut(float t) -> float {
return std::sin(t * std::numbers::pi_v<float> * 0.5F);
}
}
inline auto sineInOut(float t) -> float {
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 {
// 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 {
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 {
inline auto expoInOut(float t) -> float {
if (t == 0.0F || t == 1.0F) {
return t;
}
@@ -134,37 +134,37 @@ inline auto expoInOut(float t) -> float {
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 {
// CIRC (Circular)
inline auto circIn(float t) -> float {
return 1.0F - std::sqrt(1.0F - (t * t));
}
}
inline auto circOut(float t) -> float {
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 {
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 {
// 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 {
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 {
inline auto backInOut(float t, float overshoot = 1.70158F) -> float {
const float S = overshoot * 1.525F;
if (t < 0.5F) {
@@ -174,10 +174,10 @@ inline auto backInOut(float t, float overshoot = 1.70158F) -> float {
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 {
// 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;
}
@@ -186,9 +186,9 @@ inline auto elasticIn(float t, float amplitude = 1.0F, float period = 0.3F) -> f
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 {
inline auto elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
if (t == 0.0F || t == 1.0F) {
return t;
}
@@ -197,9 +197,9 @@ inline auto elasticOut(float t, float amplitude = 1.0F, float period = 0.3F) ->
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 {
inline auto elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) -> float {
if (t == 0.0F || t == 1.0F) {
return t;
}
@@ -215,10 +215,10 @@ inline auto elasticInOut(float t, float amplitude = 1.0F, float period = 0.3F) -
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;
}
}
// BOUNCE (Rebote - simula física de rebote)
inline auto bounceOut(float t) -> float {
// BOUNCE (Rebote - simula física de rebote)
inline auto bounceOut(float t) -> float {
const float N1 = 7.5625F;
const float D1 = 2.75F;
@@ -235,17 +235,17 @@ inline auto bounceOut(float t) -> float {
}
const float F = t - (2.625F / D1);
return (N1 * F * F) + 0.984375F;
}
}
inline auto bounceIn(float t) -> float {
inline auto bounceIn(float t) -> float {
return 1.0F - bounceOut(1.0F - t);
}
}
inline auto bounceInOut(float t) -> float {
inline auto bounceInOut(float t) -> float {
if (t < 0.5F) {
return 0.5F * bounceIn(2.0F * t);
}
return (0.5F * bounceOut((2.0F * t) - 1.0F)) + 0.5F;
}
}
} // namespace Easing