15 Commits

112 changed files with 5618 additions and 3499 deletions

View File

@@ -43,12 +43,11 @@ set(APP_SOURCES
source/core/rendering/pixel_reveal.cpp source/core/rendering/pixel_reveal.cpp
source/core/rendering/screen.cpp source/core/rendering/screen.cpp
source/core/rendering/surface.cpp source/core/rendering/surface.cpp
source/core/rendering/surface_animated_sprite.cpp source/core/rendering/sprite/animated_sprite.cpp
source/core/rendering/surface_dissolve_sprite.cpp source/core/rendering/sprite/dissolve_sprite.cpp
source/core/rendering/surface_moving_sprite.cpp source/core/rendering/sprite/moving_sprite.cpp
source/core/rendering/surface_sprite.cpp source/core/rendering/sprite/sprite.cpp
source/core/rendering/text.cpp source/core/rendering/text.cpp
source/core/rendering/texture.cpp
# Core - Locale # Core - Locale
source/core/locale/locale.cpp source/core/locale/locale.cpp
@@ -132,7 +131,11 @@ if(NOT APPLE)
if(GLSLC_EXE) if(GLSLC_EXE)
add_custom_command( add_custom_command(
OUTPUT "${SHADER_VERT_H}" "${SHADER_FRAG_H}" OUTPUT "${SHADER_VERT_H}" "${SHADER_FRAG_H}"
COMMAND "${CMAKE_SOURCE_DIR}/tools/shaders/compile_spirv.sh" COMMAND ${CMAKE_COMMAND}
-D GLSLC=${GLSLC_EXE}
-D SHADERS_DIR=${CMAKE_SOURCE_DIR}/data/shaders
-D HEADERS_DIR=${CMAKE_SOURCE_DIR}/source/core/rendering/sdl3gpu
-P ${CMAKE_SOURCE_DIR}/tools/shaders/compile_spirv.cmake
DEPENDS "${SHADER_VERT_SRC}" "${SHADER_FRAG_SRC}" DEPENDS "${SHADER_VERT_SRC}" "${SHADER_FRAG_SRC}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Compilando shaders SPIR-V..." COMMENT "Compilando shaders SPIR-V..."

View File

@@ -2,10 +2,10 @@
# lang: ca # lang: ca
title: title:
marquee: "EH JAILEROS!! ESTEM EN 2022 I ENCARA HO PETEM COM EN 1998!! QUE, HO HEU SENTIT O NO? ELS JAILGAMES HAN TORNAT!! SÍ, COLLONS, HAN TORNAT!! MÉS DE 10 TÍTOLS QUE EL JAILDOC TÉ A FOC LENT!! AIXÒ ÉS UNA BARBARITAT, PERÒ... QUIN EIXIRÀ PRIMER? I ATENCIÓ, QUE HI HA UN APARELLET NOU QUE VOS FARÀ VOLAR EL CAP: EL P.A.C.O.! PERÒ UN MOMENT... QUÈ ÉS AQUELL ENCANTET QUE VE ALLÀ? OOOH, AQUELLA MINIASCII ÉS AMOR DEL BO!! LI PEGARIA UNA MOSSEGADA A CADA BYTE! OSTRES! I NO VOS OBLIDEU DE PUJAR AQUELLS JAILGAMES VELLS I PANXUTS DE MS-DOS A GITHUB, QUE SI NO ES PERDRAN!! QUIN SERÀ EL PROPER PROJECTE DEL JAILDOC? QUÈ PRENDRA VIDA? AI MARE... NI IDEA, PERÒ ACÍ PODEU SABER-HO SI RESOLGUEU EL DILEMA DEL JAILDOCTOR... VOS ATREVIU O QUÈ?" marquee: "EI JAILERS!! ESTEM EN 2022 I ENCARA HO PETEM COM EN 1998!! QUÉ, HO HEU SENTIT O NO? ELS JAILGAMES HAN TORNAT!! SÍ, COLLONS, HAN TORNAT!! MÉS DE 10 TÍTOLS QUE EL JAILDOC TÉ A FOC LENT!! AIXÒ ÉS UNA BARBARITAT, PERÒ... QUIN EIXIRÀ PRIMER? I ATENCIÓ, QUE HI HA UN APARELLET NOU QUE VOS FARÀ VOLAR EL CAP: EL P.A.C.O.! PERÒ UN MOMENT... QUÈ ÉS AQUELLA COSETA QUE VE PER ALLÀ? OOOH, AQUELLA MINIASCII ÉS AMOR DEL BO!! LI PEGARIA UNA LLEPAETA A CADA BYTE! OSTRES! I NO VOS OBLIDEU DE PUJAR AQUELLS JAILGAMES VELLS I PANXUTS DE MS-DOS A GITHUB, QUE SI NO ES PERDRAN!! QUIN SERÀ EL PRÒXIM PROJECTE DE JAILDOC? SERÀ UN PROJECTE DE MERDA? AI MARE... NI IDEA, PERÒ ACÍ PODEU SABER-HO SI RESOLEU EL DILEMA DEL JAILDOCTOR... VOS ATREVIU O QUÈ? VAAAAA!!!"
menu: menu:
play: "1. JUGAR" play: "1. JUGAR"
keyboard: "2. REDEFINIR TECLAT" keyboard: "2. REDEFINIR TECLES"
joystick: "3. REDEFINIR MANDO" joystick: "3. REDEFINIR MANDO"
projects: "4. PROJECTES" projects: "4. PROJECTES"
keys: keys:
@@ -42,11 +42,11 @@ ending:
t6: "FOREN ALLIBERATS" t6: "FOREN ALLIBERATS"
t7: "HI HAVIA FINS I TOT BARRULLS" t7: "HI HAVIA FINS I TOT BARRULLS"
t8: "I BEGGINERS ENTRE LA GENT" t8: "I BEGGINERS ENTRE LA GENT"
t9: "BRY ESTAVA FENT LLAGRIMETA..." t9: "BRY ESTAVA PLORANT..."
t10: "PERÒ DE SOBTE ALGUNA COSA" t10: "PERÒ DE SOBTE ALGUNA COSA"
t11: "LI VA CRIDAR L'ATENCIÓ" t11: "LI VA CRIDAR L'ATENCIÓ"
t12: "UN MUNT DE FERRALLA!" t12: "UN MUNT DE FERRALLA!"
t13: "PLE D'ANDROMINES QUE NI ANAVEN!!" t13: "PLE DE TRASTOS QUE NI ANAVEN!!"
t14: "I ALESHORES," t14: "I ALESHORES,"
t15: "QUARANTA PROJECTES NOUS" t15: "QUARANTA PROJECTES NOUS"
t16: "VAN NÀIXER..." t16: "VAN NÀIXER..."
@@ -71,7 +71,7 @@ credits:
f9: "F9 VORA DE LA PANTALLA" f9: "F9 VORA DE LA PANTALLA"
author: "UN JOC DE JAILDESIGNER" author: "UN JOC DE JAILDESIGNER"
date: "FET A L'ESTIU/TARDOR DEL 2022" date: "FET A L'ESTIU/TARDOR DEL 2022"
love: "M'ENCANTEN ELS JAILGAMES!" love: "I LOVE JAILGAMES!"
achievements: achievements:
header: "ASSOLIMENT DESBLOQUEJAT!" header: "ASSOLIMENT DESBLOQUEJAT!"

View File

@@ -1,7 +1,7 @@
# ROAD TO THE JAIL # ROAD TO THE JAIL
room: room:
name_en: "ROAD TO THE JAIL" name_en: "ROAD TO THE JAIL"
name_ca: "CAMI A LA JAIL" name_ca: "CAMÍ A LA JAIL"
bgColor: black bgColor: black
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# JUMP THROUGH # JUMP THROUGH
room: room:
name_en: "JUMP THROUGH" name_en: "JUMP THROUGH"
name_ca: "SALTA A TRAVES" name_ca: "SALTA A TRAVÉS"
bgColor: black bgColor: black
border: cyan border: cyan
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# BIG JUMP # BIG JUMP
room: room:
name_en: "BIG JUMP" name_en: "BIG JUMP"
name_ca: "GRAN SALT" name_ca: "EL GRAN BOT"
bgColor: black bgColor: black
border: red border: red
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# WELCOME TO MY ABBEY # WELCOME TO MY ABBEY
room: room:
name_en: "WELCOME TO MY ABBEY" name_en: "WELCOME TO MY ABBEY"
name_ca: "BENVINGUT A LA MEVA ABADIA" name_ca: "BENVINGUT A LA MEUA ABADIA"
bgColor: blue bgColor: blue
border: yellow border: yellow
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# THE GARDEN # THE GARDEN
room: room:
name_en: "THE GARDEN" name_en: "THE GARDEN"
name_ca: "EL JARDI" name_ca: "EL JARDÍ"
bgColor: black bgColor: black
border: cyan border: cyan
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# TREE TOP # TREE TOP
room: room:
name_en: "TREE TOP" name_en: "TREE TOP"
name_ca: "AMUNT DE L'ARBRE" name_ca: "DALT DE L'ARBRE"
bgColor: bright_black bgColor: bright_black
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# LAZY ROOM # LAZY ROOM
room: room:
name_en: "LAZY ROOM" name_en: "LAZY ROOM"
name_ca: "SALA DE LA PEREA" name_ca: "LA SALA GOSSA"
bgColor: black bgColor: black
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# KILLING SPREE # KILLING SPREE
room: room:
name_en: "KILLING SPREE" name_en: "KILLING SPREE"
name_ca: "MATANCA INDISCRIMINADA" name_ca: "MATANÇA INDISCRIMINADA"
bgColor: black bgColor: black
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# NOW THIS IS THE BATCAVE! # NOW THIS IS THE BATCAVE!
room: room:
name_en: "NOW THIS IS THE BATCAVE!" name_en: "NOW THIS IS THE BATCAVE!"
name_ca: "AQUESTA SI QUE ES LA BATCOVA!" name_ca: "ESTA SI QUE ES LA BATCOVA!"
bgColor: black bgColor: black
border: black border: black
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# THE FRIDGE # THE FRIDGE
room: room:
name_en: "THE FRIDGE" name_en: "THE FRIDGE"
name_ca: "LA NEVERA" name_ca: "EL FRIGO"
bgColor: blue bgColor: blue
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# I DID NOT COPY THIS ONE # I DID NOT COPY THIS ONE
room: room:
name_en: "I DID NOT COPY THIS ONE" name_en: "I DID NOT COPY THIS ONE"
name_ca: "ESTA NO LA HE COPIADA, NO" name_ca: "ESTA NO LA HE COPIADA"
bgColor: black bgColor: black
border: magenta border: magenta
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# THIS CAN'T BE THE BATCAVE # THIS CAN'T BE THE BATCAVE
room: room:
name_en: "THIS CAN'T BE THE BATCAVE" name_en: "THIS CAN'T BE THE BATCAVE"
name_ca: "AQUESTA NO POT SER LA BATCOVA" name_ca: "ESTA NO POT SER LA BATCOVA"
bgColor: black bgColor: black
border: cyan border: cyan
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# ENTER PAKU SIMBEL # ENTER PAKU SIMBEL
room: room:
name_en: "ENTER PAKU SIMBEL" name_en: "ENTER PAKU SIMBEL"
name_ca: "ENTRANT A PAKU SIMBEL" name_ca: "ACCEDINT A PAKU SIMBEL"
bgColor: bright_black bgColor: bright_black
border: yellow border: yellow
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# YOU SHALL NOT PASS # YOU SHALL NOT PASS
room: room:
name_en: "YOU SHALL NOT PASS" name_en: "YOU SHALL NOT PASS"
name_ca: "NO PASSARAS" name_ca: "NO PASSARÀS"
bgColor: bright_black bgColor: bright_black
border: black border: black
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# QVOID IS A JAILGAME! # QVOID IS A JAILGAME!
room: room:
name_en: "QVOID IS A JAILGAME!" name_en: "QVOID IS A JAILGAME!"
name_ca: "QVOID ES UN JAILGAME!" name_ca: "QVOID ÉS UN JAILGAME!"
bgColor: blue bgColor: blue
border: bright_black border: bright_black
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# YOU'LL BELIEVE AROUNDER CAN FLY # YOU'LL BELIEVE AROUNDER CAN FLY
room: room:
name_en: "YOU'LL BELIEVE AROUNDER CAN FLY" name_en: "YOU'LL BELIEVE AROUNDER CAN FLY"
name_ca: "CREURAS QUE ELS AROUNDERS VOLEN" name_ca: "CREURÀS QUE ELS AROUNDERS VOLEN"
bgColor: black bgColor: black
border: cyan border: cyan
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# PREVENT THE CRISIS # PREVENT THE CRISIS
room: room:
name_en: "PREVENT THE CRISIS" name_en: "PREVENT THE CRISIS"
name_ca: "PREVEU LA CRISI" name_ca: "PREVÉ LA CRISI"
bgColor: black bgColor: black
border: bright_magenta border: bright_magenta
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# AROUND WITH ME # AROUND WITH ME
room: room:
name_en: "AROUND WITH ME" name_en: "AROUND WITH ME"
name_ca: "VOLTA AMB MI" name_ca: "AROUNDA AMB MI"
bgColor: black bgColor: black
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# FEEL THE PRESSURE # FEEL THE PRESSURE
room: room:
name_en: "FEEL THE PRESSURE" name_en: "FEEL THE PRESSURE"
name_ca: "NOTA LA PRESSIO" name_ca: "NOTA LA PRESSIÓ"
bgColor: bright_black bgColor: bright_black
border: bright_yellow border: bright_yellow
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# FEEL THE HEAT # FEEL THE HEAT
room: room:
name_en: "FEEL THE HEAT" name_en: "FEEL THE HEAT"
name_ca: "NOTA LA CALOR" name_ca: "NOTA EL CALORET"
bgColor: bright_black bgColor: bright_black
border: bright_yellow border: bright_yellow
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# WE NEED A ROBOT # WE NEED A ROBOT
room: room:
name_en: "WE NEED A ROBOT" name_en: "WE NEED A JAILROBOT"
name_ca: "NECESSITEM UN ROBOT" name_ca: "NECESSITEM UN JAILROBOT"
bgColor: black bgColor: black
border: red border: red
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# STORED JAILGAMES # STORED JAILGAMES
room: room:
name_en: "STORED JAILGAMES" name_en: "STORED JAILGAMES"
name_ca: "JAILGAMES EMMAGATZEMATS" name_ca: "EL MAGATZEM DE JAILGAMES"
bgColor: black bgColor: black
border: blue border: blue
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# THAT'S A GUITAR # THAT'S A GUITAR
room: room:
name_en: "THAT'S A GUITAR" name_en: "THAT'S A GUITAR"
name_ca: "AIXO ES UNA GUITARRA" name_ca: "AIXÒ ÉS UNA GUITARRA"
bgColor: black bgColor: black
border: black border: black
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# CHIRPING # CHIRPING
room: room:
name_en: "CHIRPING DEVELOPMENT" name_en: "CHIRPING"
name_ca: "DESENVOLUPANT CHIRPING" name_ca: "CHIRPING"
bgColor: black bgColor: black
border: magenta border: magenta
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# STATIC # STATIC
room: room:
name_en: "STATIC" name_en: "STATIC"
name_ca: "ESTATICA" name_ca: "ESTÀTICA"
bgColor: black bgColor: black
border: bright_magenta border: bright_magenta
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -1,7 +1,7 @@
# MAGNETIC FIELDS # MAGNETIC FIELDS
room: room:
name_en: "MAGNETIC FIELDS" name_en: "MAGNETIC FIELDS"
name_ca: "CAMPS MAGNETICS" name_ca: "CAMPS MAGNÈTICS"
bgColor: black bgColor: black
border: bright_red border: bright_red
tileSetFile: standard.gif tileSetFile: standard.gif

View File

@@ -23,9 +23,9 @@ layout(set = 3, binding = 0) uniform PostFXUniforms {
float curvature; float curvature;
float bleeding; float bleeding;
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_) float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
float time; // seconds since SDL init (for future animated effects) float time; // seconds since SDL init
float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS) float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS)
float pad1; // padding — 48 bytes total (3 × 16) float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz — 48 bytes total (3 × 16)
} u; } u;
// YCbCr helpers for NTSC bleeding // YCbCr helpers for NTSC bleeding
@@ -85,8 +85,8 @@ void main() {
colour = base; colour = base;
} }
// Aberración cromática // Aberración cromática (drift animado con time para efecto NTSC real)
float ca = u.chroma_strength * 0.005; float ca = u.chroma_strength * 0.005 * (1.0 + 0.15 * sin(u.time * 7.3));
colour.r = texture(scene, uv + vec2(ca, 0.0)).r; colour.r = texture(scene, uv + vec2(ca, 0.0)).r;
colour.b = texture(scene, uv - vec2(ca, 0.0)).b; colour.b = texture(scene, uv - vec2(ca, 0.0)).b;
@@ -96,17 +96,22 @@ void main() {
colour = mix(colour, lin, u.gamma_strength); colour = mix(colour, lin, u.gamma_strength);
} }
// Scanlines — 1 pixel físico oscuro por fila lógica. // Scanlines — proporción 2/3 brillantes + 1/3 oscuras por fila lógica.
// Usa uv.y (independiente del offset de letterbox) con pixel_scale para // Casos especiales: 1 subfila → sin efecto; 2 subfilas → 1+1 (50/50).
// calcular la posición dentro de la fila en coordenadas físicas. // Constantes ajustables:
// 3x: 1 dark + 2 bright. 4x: 1 dark + 3 bright. const float SCAN_DARK_RATIO = 0.333; // fracción de subfilas oscuras (ps >= 3)
// bright=3.5×, dark floor=0.42 (mantiene aspecto CRT original). const float SCAN_DARK_FLOOR = 0.42; // multiplicador de brillo de subfilas oscuras
if (u.scanline_strength > 0.0) { if (u.scanline_strength > 0.0) {
float ps = max(1.0, round(u.pixel_scale)); float ps = max(1.0, round(u.pixel_scale));
float frac_in_row = fract(uv.y * u.screen_height); float frac_in_row = fract(uv.y * u.screen_height);
float row_pos = floor(frac_in_row * ps); float row_pos = floor(frac_in_row * ps);
float is_dark = step(ps - 1.0, row_pos); // bright_rows: cuántas subfilas son brillantes
float scan = mix(3.5, 0.42, is_dark); // ps==1 → ps (todo brillante → is_dark nunca se activa)
// ps==2 → 1 brillante + 1 oscura
// ps>=3 → floor(ps * (1 - DARK_RATIO)) brillantes
float bright_rows = (ps < 2.0) ? ps : ((ps < 3.0) ? 1.0 : floor(ps * (1.0 - SCAN_DARK_RATIO)));
float is_dark = step(bright_rows, row_pos);
float scan = mix(1.0, SCAN_DARK_FLOOR, is_dark);
colour *= mix(1.0, scan, u.scanline_strength); colour *= mix(1.0, scan, u.scanline_strength);
} }
@@ -134,5 +139,11 @@ void main() {
colour = mix(colour, colour * mask, u.mask_strength); colour = mix(colour, colour * mask, u.mask_strength);
} }
// Parpadeo de fósforo CRT (~50 Hz)
if (u.flicker > 0.0) {
float flicker_wave = sin(u.time * 100.0) * 0.5 + 0.5;
colour *= 1.0 - u.flicker * 0.04 * flicker_wave;
}
out_color = vec4(colour, 1.0); out_color = vec4(colour, 1.0);
} }

Binary file not shown.

15
data/shaders/upscale.frag Normal file
View File

@@ -0,0 +1,15 @@
#version 450
// Vulkan GLSL fragment shader — Nearest-neighbour upscale pass
// Used as the first render pass when supersampling is active.
// Compile: glslc upscale.frag -o upscale.frag.spv
// xxd -i upscale.frag.spv > ../../source/core/rendering/sdl3gpu/upscale_frag_spv.h
layout(location = 0) in vec2 v_uv;
layout(location = 0) out vec4 out_color;
layout(set = 2, binding = 0) uniform sampler2D scene;
void main() {
out_color = texture(scene, v_uv);
}

Binary file not shown.

View File

@@ -41,7 +41,7 @@ void Audio::update() {
} }
// Reproduce la música // Reproduce la música
void Audio::playMusic(const std::string& name, const int loop) { void Audio::playMusic(const std::string& name, const int loop) { // NOLINT(readability-convert-member-functions-to-static)
bool new_loop = (loop != 0); bool new_loop = (loop != 0);
// Si ya está sonando exactamente la misma pista y mismo modo loop, no hacemos nada // Si ya está sonando exactamente la misma pista y mismo modo loop, no hacemos nada
@@ -71,7 +71,7 @@ void Audio::playMusic(const std::string& name, const int loop) {
} }
// Pausa la música // Pausa la música
void Audio::pauseMusic() { void Audio::pauseMusic() { // NOLINT(readability-convert-member-functions-to-static)
if (music_enabled_ && music_.state == MusicState::PLAYING) { if (music_enabled_ && music_.state == MusicState::PLAYING) {
JA_PauseMusic(); JA_PauseMusic();
music_.state = MusicState::PAUSED; music_.state = MusicState::PAUSED;
@@ -79,7 +79,7 @@ void Audio::pauseMusic() {
} }
// Continua la música pausada // Continua la música pausada
void Audio::resumeMusic() { void Audio::resumeMusic() { // NOLINT(readability-convert-member-functions-to-static)
if (music_enabled_ && music_.state == MusicState::PAUSED) { if (music_enabled_ && music_.state == MusicState::PAUSED) {
JA_ResumeMusic(); JA_ResumeMusic();
music_.state = MusicState::PLAYING; music_.state = MusicState::PLAYING;
@@ -87,7 +87,7 @@ void Audio::resumeMusic() {
} }
// Detiene la música // Detiene la música
void Audio::stopMusic() { void Audio::stopMusic() { // NOLINT(readability-make-member-function-const)
if (music_enabled_) { if (music_enabled_) {
JA_StopMusic(); JA_StopMusic();
music_.state = MusicState::STOPPED; music_.state = MusicState::STOPPED;

View File

@@ -24,7 +24,7 @@ namespace GlobalInputs {
if (stringInVector(Notifier::get()->getCodes(), CODE)) { if (stringInVector(Notifier::get()->getCodes(), CODE)) {
SceneManager::current = SceneManager::Scene::TITLE; SceneManager::current = SceneManager::Scene::TITLE;
} else { } else {
Notifier::get()->show({Locale::get()->get("ui.press_again_menu")}, Notifier::Style::DEFAULT, -1, true, CODE); Notifier::get()->show({Locale::get()->get("ui.press_again_menu")}, Notifier::Style::DEFAULT, -1, true, CODE); // NOLINT(readability-static-accessed-through-instance)
} }
return; return;
} }
@@ -44,7 +44,7 @@ namespace GlobalInputs {
if (stringInVector(Notifier::get()->getCodes(), CODE)) { if (stringInVector(Notifier::get()->getCodes(), CODE)) {
SceneManager::current = SceneManager::Scene::QUIT; SceneManager::current = SceneManager::Scene::QUIT;
} else { } else {
Notifier::get()->show({Locale::get()->get("ui.press_again_exit")}, Notifier::Style::DEFAULT, -1, true, CODE); Notifier::get()->show({Locale::get()->get("ui.press_again_exit")}, Notifier::Style::DEFAULT, -1, true, CODE); // NOLINT(readability-static-accessed-through-instance)
} }
} }
@@ -68,66 +68,65 @@ namespace GlobalInputs {
void handleToggleBorder() { void handleToggleBorder() {
Screen::get()->toggleBorder(); Screen::get()->toggleBorder();
Notifier::get()->show({Locale::get()->get(Options::video.border.enabled ? "ui.border_enabled" : "ui.border_disabled")}); Notifier::get()->show({Locale::get()->get(Options::video.border.enabled ? "ui.border_enabled" : "ui.border_disabled")}); // NOLINT(readability-static-accessed-through-instance)
} }
void handleToggleVideoMode() { void handleToggleVideoMode() {
Screen::get()->toggleVideoMode(); Screen::get()->toggleVideoMode();
Notifier::get()->show({Locale::get()->get(static_cast<int>(Options::video.fullscreen) == 0 ? "ui.fullscreen_disabled" : "ui.fullscreen_enabled")}); Notifier::get()->show({Locale::get()->get(static_cast<int>(Options::video.fullscreen) == 0 ? "ui.fullscreen_disabled" : "ui.fullscreen_enabled")}); // NOLINT(readability-static-accessed-through-instance)
} }
void handleDecWindowZoom() { void handleDecWindowZoom() {
if (Screen::get()->decWindowZoom()) { if (Screen::get()->decWindowZoom()) {
Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)}); Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)}); // NOLINT(readability-static-accessed-through-instance)
} }
} }
void handleIncWindowZoom() { void handleIncWindowZoom() {
if (Screen::get()->incWindowZoom()) { if (Screen::get()->incWindowZoom()) {
Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)}); Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)}); // NOLINT(readability-static-accessed-through-instance)
} }
} }
void handleTogglePostFX() { void handleTogglePostFX() {
Screen::get()->togglePostFX(); Screen::get()->togglePostFX();
Notifier::get()->show({Locale::get()->get(Options::video.postfx ? "ui.postfx_enabled" : "ui.postfx_disabled")}); Notifier::get()->show({Locale::get()->get(Options::video.postfx ? "ui.postfx_enabled" : "ui.postfx_disabled")}); // NOLINT(readability-static-accessed-through-instance)
} }
void handleToggleSupersampling() { void handleToggleSupersampling() {
Screen::get()->toggleSupersampling(); Screen::get()->toggleSupersampling();
Notifier::get()->show({Locale::get()->get(Options::video.supersampling ? "ui.supersampling_enabled" : "ui.supersampling_disabled")}); Notifier::get()->show({Locale::get()->get(Options::video.supersampling ? "ui.supersampling_enabled" : "ui.supersampling_disabled")}); // NOLINT(readability-static-accessed-through-instance)
} }
void handleNextPostFXPreset() { void handleNextPostFXPreset() {
if (!Options::postfx_presets.empty()) { if (!Options::postfx_presets.empty()) {
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size()); Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
Screen::get()->reloadPostFX(); Screen::get()->reloadPostFX();
Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name}); Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name}); // NOLINT(readability-static-accessed-through-instance)
} }
} }
void handleNextPalette() { void handleNextPalette() {
Screen::get()->nextPalette(); Screen::get()->nextPalette();
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette}); Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette}); // NOLINT(readability-static-accessed-through-instance)
} }
void handlePreviousPalette() { void handlePreviousPalette() {
Screen::get()->previousPalette(); Screen::get()->previousPalette();
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette}); Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette}); // NOLINT(readability-static-accessed-through-instance)
} }
void handleToggleIntegerScale() { void handleToggleIntegerScale() {
Screen::get()->toggleIntegerScale(); Screen::get()->toggleIntegerScale();
Screen::get()->setVideoMode(Options::video.fullscreen); Screen::get()->setVideoMode(Options::video.fullscreen);
Notifier::get()->show({Locale::get()->get(Options::video.integer_scale ? "ui.integer_scale_enabled" : "ui.integer_scale_disabled")}); Notifier::get()->show({Locale::get()->get(Options::video.integer_scale ? "ui.integer_scale_enabled" : "ui.integer_scale_disabled")}); // NOLINT(readability-static-accessed-through-instance)
} }
void handleToggleVSync() { void handleToggleVSync() {
Screen::get()->toggleVSync(); Screen::get()->toggleVSync();
Notifier::get()->show({Locale::get()->get(Options::video.vertical_sync ? "ui.vsync_enabled" : "ui.vsync_disabled")}); Notifier::get()->show({Locale::get()->get(Options::video.vertical_sync ? "ui.vsync_enabled" : "ui.vsync_disabled")}); // NOLINT(readability-static-accessed-through-instance)
} }
// Detecta qué acción global ha sido presionada (si alguna) // Detecta qué acción global ha sido presionada (si alguna)
auto getPressedAction() -> InputAction { auto getPressedAction() -> InputAction {
if (Input::get()->checkAction(InputAction::EXIT, Input::DO_NOT_ALLOW_REPEAT)) { if (Input::get()->checkAction(InputAction::EXIT, Input::DO_NOT_ALLOW_REPEAT)) {
@@ -152,12 +151,12 @@ namespace GlobalInputs {
} }
if (Input::get()->checkAction(InputAction::TOGGLE_POSTFX, Input::DO_NOT_ALLOW_REPEAT)) { if (Input::get()->checkAction(InputAction::TOGGLE_POSTFX, Input::DO_NOT_ALLOW_REPEAT)) {
if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) { if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) {
return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4 return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4
} }
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) { if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
return InputAction::NEXT_POSTFX_PRESET; // Shift+F4 return InputAction::NEXT_POSTFX_PRESET; // Shift+F4
} }
return InputAction::TOGGLE_POSTFX; // F4 return InputAction::TOGGLE_POSTFX; // F4
} }
if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) { if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
return InputAction::NEXT_PALETTE; return InputAction::NEXT_PALETTE;

View File

@@ -14,7 +14,7 @@
Input* Input::instance = nullptr; Input* Input::instance = nullptr;
// Inicializa la instancia única del singleton // Inicializa la instancia única del singleton
void Input::init(const std::string& game_controller_db_path) { void Input::init(const std::string& game_controller_db_path) { // NOLINT(readability-convert-member-functions-to-static)
Input::instance = new Input(game_controller_db_path); Input::instance = new Input(game_controller_db_path);
} }
@@ -69,7 +69,7 @@ void Input::applyKeyboardBindingsFromOptions() {
} }
// Aplica configuración de botones del gamepad desde Options al primer gamepad conectado // Aplica configuración de botones del gamepad desde Options al primer gamepad conectado
void Input::applyGamepadBindingsFromOptions() { void Input::applyGamepadBindingsFromOptions() { // NOLINT(readability-convert-member-functions-to-static)
// Si no hay gamepads conectados, no hay nada que hacer // Si no hay gamepads conectados, no hay nada que hacer
if (gamepads_.empty()) { if (gamepads_.empty()) {
return; return;
@@ -90,21 +90,21 @@ void Input::applyGamepadBindingsFromOptions() {
} }
// Asigna inputs a botones del mando // Asigna inputs a botones del mando
void Input::bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action, SDL_GamepadButton button) { void Input::bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action, SDL_GamepadButton button) { // NOLINT(readability-convert-member-functions-to-static)
if (gamepad != nullptr) { if (gamepad != nullptr) {
gamepad->bindings[action].button = button; gamepad->bindings[action].button = button;
} }
} }
// Asigna inputs a botones del mando // Asigna inputs a botones del mando
void Input::bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action_target, Action action_source) { void Input::bindGameControllerButton(const std::shared_ptr<Gamepad>& gamepad, Action action_target, Action action_source) { // NOLINT(readability-convert-member-functions-to-static)
if (gamepad != nullptr) { if (gamepad != nullptr) {
gamepad->bindings[action_target].button = gamepad->bindings[action_source].button; gamepad->bindings[action_target].button = gamepad->bindings[action_source].button;
} }
} }
// Comprueba si alguna acción está activa // Comprueba si alguna acción está activa
auto Input::checkAction(Action action, bool repeat, bool check_keyboard, const std::shared_ptr<Gamepad>& gamepad) -> bool { auto Input::checkAction(Action action, bool repeat, bool check_keyboard, const std::shared_ptr<Gamepad>& gamepad) -> bool { // NOLINT(readability-convert-member-functions-to-static)
bool success_keyboard = false; bool success_keyboard = false;
bool success_controller = false; bool success_controller = false;
@@ -142,7 +142,7 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, const s
} }
// Comprueba si hay almenos una acción activa // Comprueba si hay almenos una acción activa
auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr<Gamepad>& gamepad) -> bool { auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr<Gamepad>& gamepad) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Obtenemos el número total de acciones posibles para iterar sobre ellas. // Obtenemos el número total de acciones posibles para iterar sobre ellas.
// --- Comprobación del Teclado --- // --- Comprobación del Teclado ---
@@ -179,7 +179,7 @@ auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr<Gamepad>& g
} }
// Comprueba si hay algún botón pulsado // Comprueba si hay algún botón pulsado
auto Input::checkAnyButton(bool repeat) -> bool { auto Input::checkAnyButton(bool repeat) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Solo comprueba los botones definidos previamente // Solo comprueba los botones definidos previamente
for (auto bi : BUTTON_INPUTS) { for (auto bi : BUTTON_INPUTS) {
// Comprueba el teclado // Comprueba el teclado
@@ -219,7 +219,7 @@ auto Input::getControllerNames() const -> std::vector<std::string> {
auto Input::getNumGamepads() const -> int { return gamepads_.size(); } auto Input::getNumGamepads() const -> int { return gamepads_.size(); }
// Obtiene el gamepad a partir de un event.id // Obtiene el gamepad a partir de un event.id
auto Input::getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Input::Gamepad> { auto Input::getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Input::Gamepad> { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& gamepad : gamepads_) { for (const auto& gamepad : gamepads_) {
if (gamepad->instance_id == id) { if (gamepad->instance_id == id) {
return gamepad; return gamepad;
@@ -228,7 +228,7 @@ auto Input::getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Input::Gamepa
return nullptr; return nullptr;
} }
auto Input::getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad> { auto Input::getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad> { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& gamepad : gamepads_) { for (const auto& gamepad : gamepads_) {
if (gamepad && gamepad->name == name) { if (gamepad && gamepad->name == name) {
return gamepad; return gamepad;
@@ -238,12 +238,12 @@ auto Input::getGamepadByName(const std::string& name) const -> std::shared_ptr<I
} }
// Obtiene el SDL_GamepadButton asignado a un action // Obtiene el SDL_GamepadButton asignado a un action
auto Input::getControllerBinding(const std::shared_ptr<Gamepad>& gamepad, Action action) -> SDL_GamepadButton { auto Input::getControllerBinding(const std::shared_ptr<Gamepad>& gamepad, Action action) -> SDL_GamepadButton { // NOLINT(readability-convert-member-functions-to-static)
return static_cast<SDL_GamepadButton>(gamepad->bindings[action].button); return static_cast<SDL_GamepadButton>(gamepad->bindings[action].button);
} }
// Comprueba el eje del mando // Comprueba el eje del mando
auto Input::checkAxisInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool { auto Input::checkAxisInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Obtener el binding configurado para esta acción // Obtener el binding configurado para esta acción
auto& binding = gamepad->bindings[action]; auto& binding = gamepad->bindings[action];
@@ -286,7 +286,7 @@ auto Input::checkAxisInput(Action action, const std::shared_ptr<Gamepad>& gamepa
} }
// Comprueba los triggers del mando como botones digitales // Comprueba los triggers del mando como botones digitales
auto Input::checkTriggerInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool { auto Input::checkTriggerInput(Action action, const std::shared_ptr<Gamepad>& gamepad, bool repeat) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Solo manejamos botones específicos que pueden ser triggers // Solo manejamos botones específicos que pueden ser triggers
if (gamepad->bindings[action].button != static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID)) { if (gamepad->bindings[action].button != static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID)) {
// Solo procesamos L2 y R2 como triggers // Solo procesamos L2 y R2 como triggers
@@ -333,13 +333,13 @@ auto Input::checkTriggerInput(Action action, const std::shared_ptr<Gamepad>& gam
return false; return false;
} }
void Input::addGamepadMappingsFromFile() { void Input::addGamepadMappingsFromFile() { // NOLINT(readability-convert-member-functions-to-static)
if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) { if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) {
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << '\n'; std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << '\n';
} }
} }
void Input::discoverGamepads() { void Input::discoverGamepads() { // NOLINT(readability-convert-member-functions-to-static)
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
handleEvent(event); // Comprueba mandos conectados handleEvent(event); // Comprueba mandos conectados
@@ -375,7 +375,7 @@ void Input::resetInputStates() {
} }
} }
void Input::update() { void Input::update() { // NOLINT(readability-convert-member-functions-to-static)
// --- TECLADO --- // --- TECLADO ---
const bool* key_states = SDL_GetKeyboardState(nullptr); const bool* key_states = SDL_GetKeyboardState(nullptr);
@@ -399,7 +399,7 @@ void Input::update() {
} }
} }
auto Input::handleEvent(const SDL_Event& event) -> std::string { auto Input::handleEvent(const SDL_Event& event) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
switch (event.type) { switch (event.type) {
case SDL_EVENT_GAMEPAD_ADDED: case SDL_EVENT_GAMEPAD_ADDED:
return addGamepad(event.gdevice.which); return addGamepad(event.gdevice.which);
@@ -409,7 +409,7 @@ auto Input::handleEvent(const SDL_Event& event) -> std::string {
return {}; return {};
} }
auto Input::addGamepad(int device_index) -> std::string { auto Input::addGamepad(int device_index) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
SDL_Gamepad* pad = SDL_OpenGamepad(device_index); SDL_Gamepad* pad = SDL_OpenGamepad(device_index);
if (pad == nullptr) { if (pad == nullptr) {
std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << '\n'; std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << '\n';
@@ -423,8 +423,8 @@ auto Input::addGamepad(int device_index) -> std::string {
return name + " CONNECTED"; return name + " CONNECTED";
} }
auto Input::removeGamepad(SDL_JoystickID id) -> std::string { auto Input::removeGamepad(SDL_JoystickID id) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(gamepads_, [id](const std::shared_ptr<Gamepad>& gamepad) { auto it = std::ranges::find_if(gamepads_, [id](const std::shared_ptr<Gamepad>& gamepad) -> bool {
return gamepad->instance_id == id; return gamepad->instance_id == id;
}); });
@@ -438,7 +438,7 @@ auto Input::removeGamepad(SDL_JoystickID id) -> std::string {
return {}; return {};
} }
void Input::printConnectedGamepads() const { void Input::printConnectedGamepads() const { // NOLINT(readability-convert-member-functions-to-static)
if (gamepads_.empty()) { if (gamepads_.empty()) {
std::cout << "No hay gamepads conectados." << '\n'; std::cout << "No hay gamepads conectados." << '\n';
return; return;
@@ -452,7 +452,7 @@ void Input::printConnectedGamepads() const {
} }
} }
auto Input::findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr<Input::Gamepad> { auto Input::findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr<Input::Gamepad> { // NOLINT(readability-convert-member-functions-to-static)
// Si no hay gamepads disponibles, devolver gamepad por defecto // Si no hay gamepads disponibles, devolver gamepad por defecto
if (gamepads_.empty()) { if (gamepads_.empty()) {
return nullptr; return nullptr;

View File

@@ -101,12 +101,12 @@ class Input {
// --- Gestión de gamepads --- // --- Gestión de gamepads ---
[[nodiscard]] auto gameControllerFound() const -> bool; [[nodiscard]] auto gameControllerFound() const -> bool;
[[nodiscard]] auto getNumGamepads() const -> int; [[nodiscard]] auto getNumGamepads() const -> int;
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>; [[nodiscard]] auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
auto getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad>; [[nodiscard]] auto getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad>;
auto getGamepads() const -> const Gamepads& { return gamepads_; } [[nodiscard]] auto getGamepads() const -> const Gamepads& { return gamepads_; }
auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr<Gamepad>; auto findAvailableGamepadByName(const std::string& gamepad_name) -> std::shared_ptr<Gamepad>;
static auto getControllerName(const std::shared_ptr<Gamepad>& gamepad) -> std::string; static auto getControllerName(const std::shared_ptr<Gamepad>& gamepad) -> std::string;
auto getControllerNames() const -> std::vector<std::string>; [[nodiscard]] auto getControllerNames() const -> std::vector<std::string>;
[[nodiscard]] static auto getControllerBinding(const std::shared_ptr<Gamepad>& gamepad, Action action) -> SDL_GamepadButton; [[nodiscard]] static auto getControllerBinding(const std::shared_ptr<Gamepad>& gamepad, Action action) -> SDL_GamepadButton;
void printConnectedGamepads() const; void printConnectedGamepads() const;

View File

@@ -11,7 +11,7 @@
Locale* Locale::instance = nullptr; Locale* Locale::instance = nullptr;
// [SINGLETON] Crea el objeto con esta función estática // [SINGLETON] Crea el objeto con esta función estática
void Locale::init(const std::string& file_path) { void Locale::init(const std::string& file_path) { // NOLINT(readability-convert-member-functions-to-static)
Locale::instance = new Locale(); Locale::instance = new Locale();
Locale::instance->loadFromFile(file_path); Locale::instance->loadFromFile(file_path);
} }
@@ -28,7 +28,7 @@ auto Locale::get() -> Locale* {
} }
// Devuelve la traducción de la clave o la clave como fallback // Devuelve la traducción de la clave o la clave como fallback
auto Locale::get(const std::string& key) const -> std::string { auto Locale::get(const std::string& key) const -> std::string { // NOLINT(readability-convert-member-functions-to-static)
auto it = strings_.find(key); auto it = strings_.find(key);
if (it != strings_.end()) { if (it != strings_.end()) {
return it->second; return it->second;
@@ -41,7 +41,7 @@ auto Locale::get(const std::string& key) const -> std::string {
} }
// Aplana un nodo YAML de forma recursiva: {a: {b: "val"}} -> {"a.b" -> "val"} // Aplana un nodo YAML de forma recursiva: {a: {b: "val"}} -> {"a.b" -> "val"}
void Locale::flatten(const void* node_ptr, const std::string& prefix) { void Locale::flatten(const void* node_ptr, const std::string& prefix) { // NOLINT(readability-convert-member-functions-to-static)
const auto& node = *static_cast<const fkyaml::node*>(node_ptr); const auto& node = *static_cast<const fkyaml::node*>(node_ptr);
for (auto itr = node.begin(); itr != node.end(); ++itr) { for (auto itr = node.begin(); itr != node.end(); ++itr) {
@@ -59,7 +59,7 @@ void Locale::flatten(const void* node_ptr, const std::string& prefix) {
} }
// Carga las traducciones desde el fichero YAML indicado // Carga las traducciones desde el fichero YAML indicado
void Locale::loadFromFile(const std::string& file_path) { void Locale::loadFromFile(const std::string& file_path) { // NOLINT(readability-convert-member-functions-to-static)
if (file_path.empty()) { if (file_path.empty()) {
if (Options::console) { if (Options::console) {
std::cerr << "Locale: ruta de fichero vacía, sin traducciones cargadas\n"; std::cerr << "Locale: ruta de fichero vacía, sin traducciones cargadas\n";

View File

@@ -15,7 +15,7 @@ namespace GIF {
} }
// Inicializa el diccionario LZW con los valores iniciales // Inicializa el diccionario LZW con los valores iniciales
inline void initializeDictionary(std::vector<DictionaryEntry>& dictionary, int code_length, int& dictionary_ind) { inline void initializeDictionary(std::vector<DictionaryEntry>& dictionary, int code_length, int& dictionary_ind) { // NOLINT(readability-identifier-naming)
int size = 1 << code_length; int size = 1 << code_length;
dictionary.resize(1 << (code_length + 1)); dictionary.resize(1 << (code_length + 1));
for (dictionary_ind = 0; dictionary_ind < size; dictionary_ind++) { for (dictionary_ind = 0; dictionary_ind < size; dictionary_ind++) {
@@ -55,7 +55,7 @@ namespace GIF {
} }
// Agrega una nueva entrada al diccionario // Agrega una nueva entrada al diccionario
inline void addDictionaryEntry(std::vector<DictionaryEntry>& dictionary, int& dictionary_ind, int& code_length, int prev, int code) { inline void addDictionaryEntry(std::vector<DictionaryEntry>& dictionary, int& dictionary_ind, int& code_length, int prev, int code) { // NOLINT(readability-identifier-naming)
uint8_t first_byte; uint8_t first_byte;
if (code == dictionary_ind) { if (code == dictionary_ind) {
first_byte = findFirstByte(dictionary, prev); first_byte = findFirstByte(dictionary, prev);
@@ -90,7 +90,7 @@ namespace GIF {
return 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) { // NOLINT(readability-convert-member-functions-to-static)
// Verifica que el code_length tenga un rango razonable. // Verifica que el code_length tenga un rango razonable.
if (code_length < 2 || code_length > 12) { if (code_length < 2 || code_length > 12) {
throw std::runtime_error("Invalid LZW code length"); throw std::runtime_error("Invalid LZW code length");
@@ -146,7 +146,7 @@ namespace GIF {
} }
} }
auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> { auto Gif::readSubBlocks(const uint8_t*& buffer) -> std::vector<uint8_t> { // NOLINT(readability-convert-member-functions-to-static)
std::vector<uint8_t> data; std::vector<uint8_t> data;
uint8_t block_size = *buffer; uint8_t block_size = *buffer;
buffer++; buffer++;
@@ -159,7 +159,7 @@ namespace GIF {
return data; 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> { // NOLINT(readability-convert-member-functions-to-static)
ImageDescriptor image_descriptor; ImageDescriptor image_descriptor;
// Lee 9 bytes para el image descriptor. // Lee 9 bytes para el image descriptor.
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor)); readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
@@ -175,7 +175,7 @@ namespace GIF {
return uncompressed_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> { // NOLINT(readability-convert-member-functions-to-static)
uint8_t header[6]; uint8_t header[6];
std::memcpy(header, buffer, 6); std::memcpy(header, buffer, 6);
buffer += 6; buffer += 6;
@@ -186,7 +186,7 @@ namespace GIF {
std::vector<uint32_t> global_color_table; std::vector<uint32_t> global_color_table;
if ((screen_descriptor.fields & 0x80) != 0) { if ((screen_descriptor.fields & 0x80) != 0) {
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); int global_color_table_size = 1 << ((screen_descriptor.fields & 0x07) + 1);
global_color_table.resize(global_color_table_size); global_color_table.resize(global_color_table_size);
for (int i = 0; i < global_color_table_size; ++i) { for (int i = 0; i < global_color_table_size; ++i) {
uint8_t r = buffer[0]; uint8_t r = buffer[0];
@@ -199,7 +199,7 @@ namespace GIF {
return global_color_table; 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> { // NOLINT(readability-convert-member-functions-to-static)
// Leer la cabecera de 6 bytes ("GIF87a" o "GIF89a") // Leer la cabecera de 6 bytes ("GIF87a" o "GIF89a")
uint8_t header[6]; uint8_t header[6];
std::memcpy(header, buffer, 6); std::memcpy(header, buffer, 6);
@@ -222,7 +222,7 @@ namespace GIF {
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
std::vector<RGB> global_color_table; std::vector<RGB> global_color_table;
if ((screen_descriptor.fields & 0x80) != 0) { if ((screen_descriptor.fields & 0x80) != 0) {
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); int global_color_table_size = 1 << ((screen_descriptor.fields & 0x07) + 1);
global_color_table.resize(global_color_table_size); global_color_table.resize(global_color_table_size);
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size); std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
buffer += 3 * global_color_table_size; buffer += 3 * global_color_table_size;

View File

@@ -65,11 +65,8 @@ PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float s
} }
} }
// Destructor
PixelReveal::~PixelReveal() = default;
// Actualiza el estado del revelado // Actualiza el estado del revelado
void PixelReveal::update(float time_active) { void PixelReveal::update(float time_active) { // NOLINT(readability-make-member-function-const)
// En modo normal revela (pone transparente); en modo inverso cubre (pone negro) // En modo normal revela (pone transparente); en modo inverso cubre (pone negro)
const auto PIXEL_COLOR = reverse_ ? static_cast<Uint8>(PaletteColor::BLACK) : static_cast<Uint8>(PaletteColor::TRANSPARENT); const auto PIXEL_COLOR = reverse_ ? static_cast<Uint8>(PaletteColor::BLACK) : static_cast<Uint8>(PaletteColor::TRANSPARENT);
@@ -106,5 +103,5 @@ void PixelReveal::render(int dst_x, int dst_y) const {
// Indica si el revelado ha completado todas las filas // Indica si el revelado ha completado todas las filas
auto PixelReveal::isComplete() const -> bool { auto PixelReveal::isComplete() const -> bool {
return std::ranges::all_of(row_step_, [this](int s) { return s >= num_steps_; }); return std::ranges::all_of(row_step_, [this](int s) -> bool { return s >= num_steps_; });
} }

View File

@@ -16,8 +16,7 @@ class PixelReveal {
// Constructor // Constructor
PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4, bool reverse = false, RevealMode mode = RevealMode::RANDOM); PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4, bool reverse = false, RevealMode mode = RevealMode::RANDOM);
// Destructor definido en el .cpp para que unique_ptr<Surface> funcione con forward declaration ~PixelReveal() = default;
~PixelReveal();
// Actualiza el estado del revelado según el tiempo transcurrido // Actualiza el estado del revelado según el tiempo transcurrido
void update(float time_active); void update(float time_active);

View File

@@ -4,6 +4,7 @@
#include <algorithm> // Para max, min, transform #include <algorithm> // Para max, min, transform
#include <cctype> // Para toupper #include <cctype> // Para toupper
#include <cstring> // Para memcpy
#include <fstream> // Para basic_ostream, operator<<, endl, basic_... #include <fstream> // Para basic_ostream, operator<<, endl, basic_...
#include <iostream> // Para cerr #include <iostream> // Para cerr
#include <iterator> // Para istreambuf_iterator, operator== #include <iterator> // Para istreambuf_iterator, operator==
@@ -42,13 +43,14 @@ Screen::Screen()
: palettes_(Resource::List::get()->getListByType(Resource::List::Type::PALETTE)) { : palettes_(Resource::List::get()->getListByType(Resource::List::Type::PALETTE)) {
// Arranca SDL VIDEO, crea la ventana y el renderizador // Arranca SDL VIDEO, crea la ventana y el renderizador
initSDLVideo(); initSDLVideo();
if (Options::video.fullscreen) { if (Options::video.fullscreen) { SDL_HideCursor(); }
SDL_HideCursor();
} // Calcular tamaños y hacer .resize() de los buffers de píxeles
adjustWindowSize();
adjustRenderLogicalSize();
// Ajusta los tamaños // Ajusta los tamaños
game_surface_dstrect_ = {.x = Options::video.border.width, .y = Options::video.border.height, .w = Options::game.width, .h = Options::game.height}; game_surface_dstrect_ = {.x = Options::video.border.width, .y = Options::video.border.height, .w = Options::game.width, .h = Options::game.height};
// adjustWindowSize();
current_palette_ = findPalette(Options::video.palette); current_palette_ = findPalette(Options::video.palette);
// Define el color del borde para el modo de pantalla completa // Define el color del borde para el modo de pantalla completa
@@ -244,21 +246,28 @@ void Screen::adjustWindowSize() {
window_width_ = Options::game.width + (Options::video.border.enabled ? Options::video.border.width * 2 : 0); window_width_ = Options::game.width + (Options::video.border.enabled ? Options::video.border.width * 2 : 0);
window_height_ = Options::game.height + (Options::video.border.enabled ? Options::video.border.height * 2 : 0); window_height_ = Options::game.height + (Options::video.border.enabled ? Options::video.border.height * 2 : 0);
// Establece el nuevo tamaño // Reservamos memoria una sola vez.
// Si el buffer es más pequeño que la superficie, crash asegurado.
border_pixel_buffer_.resize(static_cast<size_t>(window_width_ * window_height_));
game_pixel_buffer_.resize(static_cast<size_t>(Options::game.width * Options::game.height));
// border_pixel_buffer_ es el buffer que se sube a la GPU (tamaño total ventana).
if (Options::video.border.enabled) {
border_pixel_buffer_.resize(static_cast<size_t>(window_width_ * window_height_));
}
// Lógica de centrado y redimensionado de ventana SDL
if (static_cast<int>(Options::video.fullscreen) == 0) { if (static_cast<int>(Options::video.fullscreen) == 0) {
int old_width; int old_w, old_h;
int old_height; SDL_GetWindowSize(window_, &old_w, &old_h);
SDL_GetWindowSize(window_, &old_width, &old_height); int old_x, old_y;
SDL_GetWindowPosition(window_, &old_x, &old_y);
int old_pos_x; const int NEW_X = old_x + ((old_w - (window_width_ * Options::window.zoom)) / 2);
int old_pos_y; const int NEW_Y = old_y + ((old_h - (window_height_ * Options::window.zoom)) / 2);
SDL_GetWindowPosition(window_, &old_pos_x, &old_pos_y);
const int NEW_POS_X = old_pos_x + ((old_width - (window_width_ * Options::window.zoom)) / 2);
const int NEW_POS_Y = old_pos_y + ((old_height - (window_height_ * Options::window.zoom)) / 2);
SDL_SetWindowSize(window_, window_width_ * Options::window.zoom, window_height_ * Options::window.zoom); SDL_SetWindowSize(window_, window_width_ * Options::window.zoom, window_height_ * Options::window.zoom);
SDL_SetWindowPosition(window_, std::max(NEW_POS_X, WINDOWS_DECORATIONS), std::max(NEW_POS_Y, 0)); SDL_SetWindowPosition(window_, std::max(NEW_X, WINDOWS_DECORATIONS), std::max(NEW_Y, 0));
} }
} }
@@ -294,7 +303,7 @@ void Screen::previousPalette() {
} }
// Establece la paleta // Establece la paleta
void Screen::setPalete() { void Screen::setPalete() { // NOLINT(readability-convert-member-functions-to-static)
game_surface_->loadPalette(Resource::Cache::get()->getPalette(palettes_.at(current_palette_))); game_surface_->loadPalette(Resource::Cache::get()->getPalette(palettes_.at(current_palette_)));
border_surface_->loadPalette(Resource::Cache::get()->getPalette(palettes_.at(current_palette_))); border_surface_->loadPalette(Resource::Cache::get()->getPalette(palettes_.at(current_palette_)));
@@ -318,7 +327,7 @@ void Screen::processPaletteList() {
} }
// Copia la surface a la textura // Copia la surface a la textura
void Screen::surfaceToTexture() { void Screen::surfaceToTexture() { // NOLINT(readability-convert-member-functions-to-static)
if (Options::video.border.enabled) { if (Options::video.border.enabled) {
border_surface_->copyToTexture(renderer_, border_texture_); border_surface_->copyToTexture(renderer_, border_texture_);
game_surface_->copyToTexture(renderer_, border_texture_, nullptr, &game_surface_dstrect_); game_surface_->copyToTexture(renderer_, border_texture_, nullptr, &game_surface_dstrect_);
@@ -329,44 +338,48 @@ void Screen::surfaceToTexture() {
// Copia la textura al renderizador (o hace el present GPU) // Copia la textura al renderizador (o hace el present GPU)
void Screen::textureToRenderer() { void Screen::textureToRenderer() {
SDL_Texture* texture_to_render = Options::video.border.enabled ? border_texture_ : game_texture_;
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) { if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
// ---- SDL3 GPU path: convertir Surface → ARGB → upload → PostFX/pass-through → present ---- const int GAME_W = Options::game.width;
if (Options::video.border.enabled) { const int GAME_H = Options::game.height;
// El border_surface_ solo tiene el color de borde; hay que componer encima el game_surface_
const int BORDER_W = static_cast<int>(border_surface_->getWidth());
const int BORDER_H = static_cast<int>(border_surface_->getHeight());
pixel_buffer_.resize(static_cast<size_t>(BORDER_W * BORDER_H));
border_surface_->toARGBBuffer(pixel_buffer_.data());
// Compositar game_surface_ en la posición correcta dentro del buffer if (Options::video.border.enabled) {
const int GAME_W = static_cast<int>(game_surface_->getWidth()); // 1. Volcamos la Surface del borde al buffer (aquí van las franjas de carga)
const int GAME_H = static_cast<int>(game_surface_->getHeight()); // Esto es mucho más rápido que un bucle manual
border_surface_->toARGBBuffer(border_pixel_buffer_.data());
// 2. Extraemos los píxeles del juego
game_surface_->toARGBBuffer(game_pixel_buffer_.data());
// 3. Superponemos el juego sobre el borde (Composición por filas)
const int BORDER_W = window_width_;
const int OFF_X = static_cast<int>(game_surface_dstrect_.x); const int OFF_X = static_cast<int>(game_surface_dstrect_.x);
const int OFF_Y = static_cast<int>(game_surface_dstrect_.y); const int OFF_Y = static_cast<int>(game_surface_dstrect_.y);
std::vector<Uint32> game_pixels(static_cast<size_t>(GAME_W * GAME_H));
game_surface_->toARGBBuffer(game_pixels.data());
for (int y = 0; y < GAME_H; ++y) { for (int y = 0; y < GAME_H; ++y) {
for (int x = 0; x < GAME_W; ++x) { // Puntero de origen (fila Y del juego)
pixel_buffer_[static_cast<size_t>(((OFF_Y + y) * BORDER_W) + (OFF_X + x))] = game_pixels[static_cast<size_t>((y * GAME_W) + x)]; const Uint32* src = &game_pixel_buffer_[y * GAME_W];
} // Puntero de destino (fila Y + offset en el buffer global)
Uint32* dst = &border_pixel_buffer_[(OFF_Y + y) * BORDER_W + OFF_X];
// Copia de bloque de memoria (muy eficiente)
std::memcpy(dst, src, GAME_W * sizeof(Uint32));
} }
shader_backend_->uploadPixels(pixel_buffer_.data(), BORDER_W, BORDER_H);
// 4. Subida final de un único buffer completo
shader_backend_->uploadPixels(border_pixel_buffer_.data(), BORDER_W, window_height_);
} else { } else {
const int GAME_W = static_cast<int>(game_surface_->getWidth()); // Caso sin borde: subida directa simplificada
const int GAME_H = static_cast<int>(game_surface_->getHeight()); game_surface_->toARGBBuffer(game_pixel_buffer_.data());
pixel_buffer_.resize(static_cast<size_t>(GAME_W * GAME_H)); shader_backend_->uploadPixels(game_pixel_buffer_.data(), GAME_W, GAME_H);
game_surface_->toARGBBuffer(pixel_buffer_.data());
shader_backend_->uploadPixels(pixel_buffer_.data(), GAME_W, GAME_H);
} }
shader_backend_->render(); shader_backend_->render();
} else { } else {
// ---- SDL_Renderer path (fallback / no-shader) ---- // Fallback SDL_Renderer (mantiene tu lógica de texturas SDL)
SDL_Texture* tex = Options::video.border.enabled ? border_texture_ : game_texture_;
SDL_SetRenderTarget(renderer_, nullptr); SDL_SetRenderTarget(renderer_, nullptr);
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
SDL_RenderTexture(renderer_, texture_to_render, nullptr, nullptr); SDL_RenderTexture(renderer_, tex, nullptr, nullptr);
SDL_RenderPresent(renderer_); SDL_RenderPresent(renderer_);
} }
} }
@@ -380,7 +393,7 @@ void Screen::renderOverlays() {
} }
// Localiza la paleta dentro del vector de paletas // Localiza la paleta dentro del vector de paletas
auto Screen::findPalette(const std::string& name) -> size_t { auto Screen::findPalette(const std::string& name) -> size_t { // NOLINT(readability-convert-member-functions-to-static)
std::string upper_name = toUpper(name + ".pal"); std::string upper_name = toUpper(name + ".pal");
for (size_t i = 0; i < palettes_.size(); ++i) { for (size_t i = 0; i < palettes_.size(); ++i) {
@@ -393,18 +406,45 @@ auto Screen::findPalette(const std::string& name) -> size_t {
// Muestra información por pantalla // Muestra información por pantalla
void Screen::renderInfo() const { void Screen::renderInfo() const {
if (show_fps_ && (Resource::Cache::get() != nullptr)) { if (!show_fps_ || text_ == nullptr) {
auto text = Resource::Cache::get()->getText("smb2"); return;
auto color = static_cast<Uint8>(PaletteColor::YELLOW);
auto shadow = static_cast<Uint8>(PaletteColor::BLACK);
// FPS con sombra
const std::string FPS_TEXT = std::to_string(fps_.last_value) + " FPS";
const int FPS_X = Options::game.width - text->length(FPS_TEXT) - 1;
text->writeColored(FPS_X + 1, 1, FPS_TEXT, shadow);
text->writeColored(FPS_X, 0, FPS_TEXT, color);
} }
const int LINE_HEIGHT = text_->getCharacterSize() - 3;
const int X = 0;
int y = 0;
// FPS
const std::string FPS_TEXT = std::to_string(fps_.last_value) + " fps";
text_->write(X, y, FPS_TEXT);
y += LINE_HEIGHT;
// Driver GPU
text_->write(X, y, gpu_driver_.empty() ? "sdl" : gpu_driver_);
y += LINE_HEIGHT;
// Zoom de la ventana
const std::string ZOOM_TEXT = "zoom x" + std::to_string(Options::window.zoom);
text_->write(X, y, ZOOM_TEXT);
y += LINE_HEIGHT;
// PostFX enabled
const std::string POSTFX_TEXT = std::string("postfx ") + (Options::video.postfx ? "on" : "off");
text_->write(X, y, POSTFX_TEXT);
y += LINE_HEIGHT;
// PostFX preset
std::string preset_name = "-";
if (!Options::postfx_presets.empty()) {
preset_name = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name;
}
const std::string PRESET_TEXT = "preset " + preset_name;
text_->write(X, y, PRESET_TEXT);
y += LINE_HEIGHT;
// Supersampling enabled
const std::string SS_TEXT = std::string("ss ") + (Options::video.supersampling ? "on" : "off");
text_->write(X, y, SS_TEXT);
} }
// Limpia la game_surface_ // Limpia la game_surface_
@@ -468,14 +508,14 @@ void Screen::toggleSupersampling() {
} }
// Aplica los parámetros del preset actual al backend de shaders // Aplica los parámetros del preset actual al backend de shaders
void Screen::applyCurrentPostFXPreset() { void Screen::applyCurrentPostFXPreset() { // NOLINT(readability-convert-member-functions-to-static)
if (shader_backend_ && !Options::postfx_presets.empty()) { if (shader_backend_ && !Options::postfx_presets.empty()) {
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)]; const auto& p = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)];
// Supersampling es un toggle global (Options::video.supersampling), no por preset. // Supersampling es un toggle global (Options::video.supersampling), no por preset.
// setOversample primero: puede recrear texturas antes de que setPostFXParams // setOversample primero: puede recrear texturas antes de que setPostFXParams
// decida si hornear scanlines en CPU o aplicarlas en GPU. // decida si hornear scanlines en CPU o aplicarlas en GPU.
shader_backend_->setOversample(Options::video.supersampling ? 3 : 1); shader_backend_->setOversample(Options::video.supersampling ? 3 : 1);
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = 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, .flicker = p.flicker};
shader_backend_->setPostFXParams(params); shader_backend_->setPostFXParams(params);
} }
} }
@@ -490,6 +530,7 @@ void Screen::initShaders() {
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>(); shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
} }
shader_backend_->init(window_, tex, "", ""); shader_backend_->init(window_, tex, "", "");
gpu_driver_ = shader_backend_->getDriverName();
// Propagar flags de vsync e integer scale al backend GPU // Propagar flags de vsync e integer scale al backend GPU
shader_backend_->setVSync(Options::video.vertical_sync); shader_backend_->setVSync(Options::video.vertical_sync);
@@ -504,7 +545,7 @@ void Screen::initShaders() {
} }
// Obtiene información sobre la pantalla // Obtiene información sobre la pantalla
void Screen::getDisplayInfo() { void Screen::getDisplayInfo() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n** VIDEO SYSTEM **\n"; std::cout << "\n** VIDEO SYSTEM **\n";
int num_displays = 0; int num_displays = 0;
@@ -609,7 +650,7 @@ auto Screen::initSDLVideo() -> bool {
} }
// Crea el objeto de texto // Crea el objeto de texto
void Screen::createText() { void Screen::createText() { // NOLINT(readability-convert-member-functions-to-static)
// Carga la surface de la fuente directamente del archivo // Carga la surface de la fuente directamente del archivo
auto surface = std::make_shared<Surface>(Resource::List::get()->get("aseprite.gif")); auto surface = std::make_shared<Surface>(Resource::List::get()->get("aseprite.gif"));

View File

@@ -53,12 +53,12 @@ class Screen {
void toggleBorder(); // Cambia entre borde visible y no visible void toggleBorder(); // Cambia entre borde visible y no visible
// Paletas y PostFX // Paletas y PostFX
void nextPalette(); // Cambia a la siguiente paleta void nextPalette(); // Cambia a la siguiente paleta
void previousPalette(); // Cambia a la paleta anterior void previousPalette(); // Cambia a la paleta anterior
void setPalete(); // Establece la paleta actual void setPalete(); // Establece la paleta actual
void togglePostFX(); // Cambia el estado del PostFX void togglePostFX(); // Cambia el estado del PostFX
void toggleSupersampling(); // Activa/desactiva el supersampling global void toggleSupersampling(); // Activa/desactiva el supersampling global
void reloadPostFX(); // Recarga el shader del preset actual sin toggle void reloadPostFX(); // Recarga el shader del preset actual sin toggle
// Surfaces y notificaciones // Surfaces y notificaciones
void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces
@@ -139,6 +139,10 @@ class Screen {
std::unique_ptr<Rendering::ShaderBackend> shader_backend_; // Backend de shaders (OpenGL/Metal/Vulkan) std::unique_ptr<Rendering::ShaderBackend> shader_backend_; // Backend de shaders (OpenGL/Metal/Vulkan)
std::shared_ptr<Text> text_; // Objeto para escribir texto std::shared_ptr<Text> text_; // Objeto para escribir texto
// Buffers persistentes para evitar .resize() cada frame
std::vector<Uint32> game_pixel_buffer_; // Textura de juego
std::vector<Uint32> border_pixel_buffer_; // Textura de borde
// Configuración de ventana y pantalla // Configuración de ventana y pantalla
int window_width_{0}; // Ancho de la pantalla o ventana int window_width_{0}; // Ancho de la pantalla o ventana
int window_height_{0}; // Alto de la pantalla o ventana int window_height_{0}; // Alto de la pantalla o ventana
@@ -156,10 +160,11 @@ class Screen {
// Shaders // Shaders
std::string info_resolution_; // Texto con la información de la pantalla std::string info_resolution_; // Texto con la información de la pantalla
std::string gpu_driver_; // Nombre del driver GPU (SDL3GPU), capturado en initShaders()
std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB) std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
#ifdef _DEBUG #ifdef _DEBUG
bool show_fps_{true}; // Indica si ha de mostrar el contador de FPS bool show_fps_{true}; // Indica si ha de mostrar el contador de FPS
#else #else
bool show_fps_{false}; // Indica si ha de mostrar el contador de FPS bool show_fps_{false}; // Indica si ha de mostrar el contador de FPS
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1445,5 +1445,6 @@ static const uint8_t kpostfx_vert_spv[] = {
0x38, 0x38,
0x00, 0x00,
0x01, 0x01,
0x00}; 0x00,
};
static const size_t kpostfx_vert_spv_size = 1444; static const size_t kpostfx_vert_spv_size = 1444;

View File

@@ -9,6 +9,7 @@
#ifndef __APPLE__ #ifndef __APPLE__
#include "core/rendering/sdl3gpu/postfx_frag_spv.h" #include "core/rendering/sdl3gpu/postfx_frag_spv.h"
#include "core/rendering/sdl3gpu/postfx_vert_spv.h" #include "core/rendering/sdl3gpu/postfx_vert_spv.h"
#include "core/rendering/sdl3gpu/upscale_frag_spv.h"
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
@@ -57,7 +58,7 @@ struct PostFXUniforms {
float pixel_scale; float pixel_scale;
float time; float time;
float oversample; // 1.0 = sin SS, 3.0 = 3× supersampling float oversample; // 1.0 = sin SS, 3.0 = 3× supersampling
float pad1; float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz
}; };
// YCbCr helpers for NTSC bleeding // YCbCr helpers for NTSC bleeding
@@ -119,8 +120,8 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
colour = base; colour = base;
} }
// Aberración cromática // Aberración cromática (drift animado con time para efecto NTSC real)
float ca = u.chroma_strength * 0.005f; float ca = u.chroma_strength * 0.005f * (1.0f + 0.15f * sin(u.time * 7.3f));
colour.r = scene.sample(samp, uv + float2(ca, 0.0f)).r; colour.r = scene.sample(samp, uv + float2(ca, 0.0f)).r;
colour.b = scene.sample(samp, uv - float2(ca, 0.0f)).b; colour.b = scene.sample(samp, uv - float2(ca, 0.0f)).b;
@@ -130,17 +131,18 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
colour = mix(colour, lin, u.gamma_strength); colour = mix(colour, lin, u.gamma_strength);
} }
// Scanlines — 1 pixel físico oscuro por fila lógica. // Scanlines — proporción 2/3 brillantes + 1/3 oscuras por fila lógica.
// Usa uv.y (independiente del offset de letterbox) con pixel_scale para // Casos especiales: 1 subfila → sin efecto; 2 subfilas → 1+1 (50/50).
// calcular la posición dentro de la fila en coordenadas físicas. // Constantes ajustables:
// 3x: 1 dark + 2 bright. 4x: 1 dark + 3 bright. const float SCAN_DARK_RATIO = 0.333f; // fracción de subfilas oscuras (ps >= 3)
// bright=3.5×, dark floor=0.42 (mantiene aspecto CRT original). const float SCAN_DARK_FLOOR = 0.42f; // multiplicador de brillo de subfilas oscuras
if (u.scanline_strength > 0.0f) { if (u.scanline_strength > 0.0f) {
float ps = max(1.0f, round(u.pixel_scale)); float ps = max(1.0f, round(u.pixel_scale));
float frac_in_row = fract(uv.y * u.screen_height); float frac_in_row = fract(uv.y * u.screen_height);
float row_pos = floor(frac_in_row * ps); float row_pos = floor(frac_in_row * ps);
float is_dark = step(ps - 1.0f, row_pos); float bright_rows = (ps < 2.0f) ? ps : ((ps < 3.0f) ? 1.0f : floor(ps * (1.0f - SCAN_DARK_RATIO)));
float scan = mix(3.5f, 0.42f, is_dark); float is_dark = step(bright_rows, row_pos);
float scan = mix(1.0f, SCAN_DARK_FLOOR, is_dark);
colour *= mix(1.0f, scan, u.scanline_strength); colour *= mix(1.0f, scan, u.scanline_strength);
} }
@@ -165,9 +167,26 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
colour = mix(colour, colour * mask, u.mask_strength); colour = mix(colour, colour * mask, u.mask_strength);
} }
// Parpadeo de fósforo CRT (~50 Hz)
if (u.flicker > 0.0f) {
float flicker_wave = sin(u.time * 100.0f) * 0.5f + 0.5f;
colour *= 1.0f - u.flicker * 0.04f * flicker_wave;
}
return float4(colour, 1.0f); return float4(colour, 1.0f);
} }
)"; )";
static const char* UPSCALE_FRAG_MSL = R"(
#include <metal_stdlib>
using namespace metal;
struct VertOut { float4 pos [[position]]; float2 uv; };
fragment float4 upscale_fs(VertOut in [[stage_in]],
texture2d<float> scene [[texture(0)]],
sampler smp [[sampler(0)]])
{
return scene.sample(smp, in.uv);
}
)";
// NOLINTEND(readability-identifier-naming) // NOLINTEND(readability-identifier-naming)
#endif // __APPLE__ #endif // __APPLE__
@@ -201,12 +220,10 @@ namespace Rendering {
float fw = 0.0F; float fw = 0.0F;
float fh = 0.0F; float fh = 0.0F;
SDL_GetTextureSize(texture, &fw, &fh); SDL_GetTextureSize(texture, &fw, &fh);
game_width_ = static_cast<int>(fw); game_width_ = static_cast<int>(fw);
game_height_ = static_cast<int>(fh); game_height_ = static_cast<int>(fh);
tex_width_ = game_width_ * oversample_; uniforms_.screen_height = static_cast<float>(game_height_);
tex_height_ = game_height_ * oversample_; uniforms_.oversample = static_cast<float>(oversample_);
uniforms_.screen_height = static_cast<float>(tex_height_); // Altura de la textura GPU
uniforms_.oversample = static_cast<float>(oversample_);
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// 1. Create GPU device (solo si no existe ya) // 1. Create GPU device (solo si no existe ya)
@@ -222,7 +239,8 @@ namespace Rendering {
SDL_Log("SDL3GPUShader: SDL_CreateGPUDevice failed: %s", SDL_GetError()); SDL_Log("SDL3GPUShader: SDL_CreateGPUDevice failed: %s", SDL_GetError());
return false; return false;
} }
SDL_Log("SDL3GPUShader: driver = %s", SDL_GetGPUDeviceDriver(device_)); driver_name_ = SDL_GetGPUDeviceDriver(device_);
SDL_Log("SDL3GPUShader: driver = %s", driver_name_.c_str());
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// 2. Claim window (una sola vez — no liberar hasta destroy()) // 2. Claim window (una sola vez — no liberar hasta destroy())
@@ -237,15 +255,15 @@ namespace Rendering {
} }
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// 3. Create scene texture (upload target + sampler source) // 3. Create scene texture (upload target, always game resolution)
// Format: B8G8R8A8_UNORM matches SDL ARGB8888 byte layout on LE // Format: B8G8R8A8_UNORM matches SDL ARGB8888 byte layout on LE
// ---------------------------------------------------------------- // ----------------------------------------------------------------
SDL_GPUTextureCreateInfo tex_info = {}; SDL_GPUTextureCreateInfo tex_info = {};
tex_info.type = SDL_GPU_TEXTURETYPE_2D; tex_info.type = SDL_GPU_TEXTURETYPE_2D;
tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM; tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
tex_info.width = static_cast<Uint32>(tex_width_); tex_info.width = static_cast<Uint32>(game_width_);
tex_info.height = static_cast<Uint32>(tex_height_); tex_info.height = static_cast<Uint32>(game_height_);
tex_info.layer_count_or_depth = 1; tex_info.layer_count_or_depth = 1;
tex_info.num_levels = 1; tex_info.num_levels = 1;
scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info); scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info);
@@ -255,12 +273,15 @@ namespace Rendering {
return false; return false;
} }
// scaled_texture_ se creará en el primer render() una vez conocido el zoom de ventana
ss_factor_ = 0;
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// 4. Create upload transfer buffer (CPU → GPU, size = w*h*4 bytes) // 4. Create upload transfer buffer (CPU → GPU, always game resolution)
// ---------------------------------------------------------------- // ----------------------------------------------------------------
SDL_GPUTransferBufferCreateInfo tb_info = {}; SDL_GPUTransferBufferCreateInfo tb_info = {};
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
tb_info.size = static_cast<Uint32>(tex_width_ * tex_height_ * 4); tb_info.size = static_cast<Uint32>(game_width_ * game_height_ * 4);
upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info); upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info);
if (upload_buffer_ == nullptr) { if (upload_buffer_ == nullptr) {
SDL_Log("SDL3GPUShader: failed to create upload buffer: %s", SDL_GetError()); SDL_Log("SDL3GPUShader: failed to create upload buffer: %s", SDL_GetError());
@@ -308,7 +329,7 @@ namespace Rendering {
} }
is_initialized_ = true; is_initialized_ = true;
SDL_Log("SDL3GPUShader: initialized OK (%dx%d)", tex_width_, tex_height_); SDL_Log("SDL3GPUShader: initialized OK — game %dx%d, oversample %d", game_width_, game_height_, oversample_);
return true; return true;
} }
@@ -318,6 +339,7 @@ namespace Rendering {
auto SDL3GPUShader::createPipeline() -> bool { auto SDL3GPUShader::createPipeline() -> bool {
const SDL_GPUTextureFormat SWAPCHAIN_FMT = SDL_GetGPUSwapchainTextureFormat(device_, window_); const SDL_GPUTextureFormat SWAPCHAIN_FMT = SDL_GetGPUSwapchainTextureFormat(device_, window_);
// ---- PostFX pipeline (scene/scaled → swapchain) ----
#ifdef __APPLE__ #ifdef __APPLE__
SDL_GPUShader* vert = createShaderMSL(device_, POSTFX_VERT_MSL, "postfx_vs", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0); SDL_GPUShader* vert = createShaderMSL(device_, POSTFX_VERT_MSL, "postfx_vs", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
SDL_GPUShader* frag = createShaderMSL(device_, POSTFX_FRAG_MSL, "postfx_fs", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1); SDL_GPUShader* frag = createShaderMSL(device_, POSTFX_FRAG_MSL, "postfx_fs", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1);
@@ -357,9 +379,48 @@ namespace Rendering {
SDL_ReleaseGPUShader(device_, frag); SDL_ReleaseGPUShader(device_, frag);
if (pipeline_ == nullptr) { if (pipeline_ == nullptr) {
SDL_Log("SDL3GPUShader: pipeline creation failed: %s", SDL_GetError()); SDL_Log("SDL3GPUShader: PostFX pipeline creation failed: %s", SDL_GetError());
return false; return false;
} }
// ---- Upscale pipeline (scene → scaled_texture_, nearest) ----
#ifdef __APPLE__
SDL_GPUShader* uvert = createShaderMSL(device_, POSTFX_VERT_MSL, "postfx_vs", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
SDL_GPUShader* ufrag = createShaderMSL(device_, UPSCALE_FRAG_MSL, "upscale_fs", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0);
#else
SDL_GPUShader* uvert = createShaderSPIRV(device_, kpostfx_vert_spv, kpostfx_vert_spv_size, "main", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
SDL_GPUShader* ufrag = createShaderSPIRV(device_, kupscale_frag_spv, kupscale_frag_spv_size, "main", SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0);
#endif
if ((uvert == nullptr) || (ufrag == nullptr)) {
SDL_Log("SDL3GPUShader: failed to compile upscale shaders");
if (uvert != nullptr) { SDL_ReleaseGPUShader(device_, uvert); }
if (ufrag != nullptr) { SDL_ReleaseGPUShader(device_, ufrag); }
return false;
}
SDL_GPUColorTargetDescription upscale_color_target = {};
upscale_color_target.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
upscale_color_target.blend_state = no_blend;
SDL_GPUGraphicsPipelineCreateInfo upscale_pipe_info = {};
upscale_pipe_info.vertex_shader = uvert;
upscale_pipe_info.fragment_shader = ufrag;
upscale_pipe_info.vertex_input_state = no_input;
upscale_pipe_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
upscale_pipe_info.target_info.num_color_targets = 1;
upscale_pipe_info.target_info.color_target_descriptions = &upscale_color_target;
upscale_pipeline_ = SDL_CreateGPUGraphicsPipeline(device_, &upscale_pipe_info);
SDL_ReleaseGPUShader(device_, uvert);
SDL_ReleaseGPUShader(device_, ufrag);
if (upscale_pipeline_ == nullptr) {
SDL_Log("SDL3GPUShader: upscale pipeline creation failed: %s", SDL_GetError());
return false;
}
return true; return true;
} }
@@ -377,43 +438,8 @@ namespace Rendering {
return; return;
} }
if (oversample_ <= 1) { // Copia directa — el upscale lo hace la GPU en el primer render pass
// Path sin supersampling: copia directa std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4));
std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4));
} else {
// Path con supersampling: expande cada pixel a OS×OS, oscurece última fila.
// Replica la fórmula del shader: mix(3.5, 0.42, scanline_strength).
auto* out = static_cast<Uint32*>(mapped);
const int OS = oversample_;
const float BRIGHT_MUL = 1.0F + (baked_scanline_strength_ * 2.5F); // rows 0..OS-2
const float DARK_MUL = 1.0F - (baked_scanline_strength_ * 0.58F); // row OS-1
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
const Uint32 SRC = pixels[y * width + x];
const Uint32 ALPHA = (SRC >> 24) & 0xFFU;
const auto FR = static_cast<float>((SRC >> 16) & 0xFFU);
const auto FG = static_cast<float>((SRC >> 8) & 0xFFU);
const auto FB = static_cast<float>( SRC & 0xFFU);
auto make_px = [ALPHA](float rv, float gv, float bv) -> Uint32 {
auto cl = [](float v) -> Uint32 { return static_cast<Uint32>(std::min(255.0F, v)); };
return (ALPHA << 24) | (cl(rv) << 16) | (cl(gv) << 8) | cl(bv);
};
const Uint32 BRIGHT = make_px(FR * BRIGHT_MUL, FG * BRIGHT_MUL, FB * BRIGHT_MUL);
const Uint32 DARK = make_px(FR * DARK_MUL, FG * DARK_MUL, FB * DARK_MUL);
for (int dy = 0; dy < OS; ++dy) {
const Uint32 OUT_PX = (dy == OS - 1) ? DARK : BRIGHT;
const int DST_Y = (y * OS) + dy;
for (int dx = 0; dx < OS; ++dx) {
out[DST_Y * (width * OS) + (x * OS) + dx] = OUT_PX;
}
}
}
}
}
SDL_UnmapGPUTransferBuffer(device_, upload_buffer_); SDL_UnmapGPUTransferBuffer(device_, upload_buffer_);
} }
@@ -424,31 +450,64 @@ namespace Rendering {
void SDL3GPUShader::render() { void SDL3GPUShader::render() {
if (!is_initialized_) { return; } if (!is_initialized_) { return; }
// Paso 0: si SS activo, calcular el factor necesario según el zoom actual y recrear si cambió.
// Factor = primer múltiplo de 3 >= zoom (mín 3). Se recrea solo en saltos de factor.
if (oversample_ > 1 && game_height_ > 0) {
int win_w = 0;
int win_h = 0;
SDL_GetWindowSizeInPixels(window_, &win_w, &win_h);
const float ZOOM = static_cast<float>(win_h) / static_cast<float>(game_height_);
const int NEED_FACTOR = calcSsFactor(ZOOM);
if (NEED_FACTOR != ss_factor_) {
SDL_WaitForGPUIdle(device_);
recreateScaledTexture(NEED_FACTOR);
}
}
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_); SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_);
if (cmd == nullptr) { if (cmd == nullptr) {
SDL_Log("SDL3GPUShader: SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError()); SDL_Log("SDL3GPUShader: SDL_AcquireGPUCommandBuffer failed: %s", SDL_GetError());
return; return;
} }
// ---- Copy pass: transfer buffer → scene texture ---- // ---- Copy pass: transfer buffer → scene texture (siempre a resolución del juego) ----
SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd); SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);
if (copy != nullptr) { if (copy != nullptr) {
SDL_GPUTextureTransferInfo src = {}; SDL_GPUTextureTransferInfo src = {};
src.transfer_buffer = upload_buffer_; src.transfer_buffer = upload_buffer_;
src.offset = 0; src.offset = 0;
src.pixels_per_row = static_cast<Uint32>(tex_width_); src.pixels_per_row = static_cast<Uint32>(game_width_);
src.rows_per_layer = static_cast<Uint32>(tex_height_); src.rows_per_layer = static_cast<Uint32>(game_height_);
SDL_GPUTextureRegion dst = {}; SDL_GPUTextureRegion dst = {};
dst.texture = scene_texture_; dst.texture = scene_texture_;
dst.w = static_cast<Uint32>(tex_width_); dst.w = static_cast<Uint32>(game_width_);
dst.h = static_cast<Uint32>(tex_height_); dst.h = static_cast<Uint32>(game_height_);
dst.d = 1; dst.d = 1;
SDL_UploadToGPUTexture(copy, &src, &dst, false); SDL_UploadToGPUTexture(copy, &src, &dst, false);
SDL_EndGPUCopyPass(copy); SDL_EndGPUCopyPass(copy);
} }
// ---- Upscale pass: scene_texture_ (game res) → scaled_texture_ (game × OS) ----
if (oversample_ > 1 && scaled_texture_ != nullptr && upscale_pipeline_ != nullptr) {
SDL_GPUColorTargetInfo upscale_target = {};
upscale_target.texture = scaled_texture_;
upscale_target.load_op = SDL_GPU_LOADOP_DONT_CARE;
upscale_target.store_op = SDL_GPU_STOREOP_STORE;
SDL_GPURenderPass* upass = SDL_BeginGPURenderPass(cmd, &upscale_target, 1, nullptr);
if (upass != nullptr) {
SDL_BindGPUGraphicsPipeline(upass, upscale_pipeline_);
SDL_GPUTextureSamplerBinding ubinding = {};
ubinding.texture = scene_texture_;
ubinding.sampler = sampler_; // NEAREST
SDL_BindGPUFragmentSamplers(upass, 0, &ubinding, 1);
SDL_DrawGPUPrimitives(upass, 3, 1, 0, 0);
SDL_EndGPURenderPass(upass);
}
}
// ---- Acquire swapchain texture ---- // ---- Acquire swapchain texture ----
SDL_GPUTexture* swapchain = nullptr; SDL_GPUTexture* swapchain = nullptr;
Uint32 sw = 0; Uint32 sw = 0;
@@ -495,24 +554,33 @@ namespace Rendering {
} }
vx = std::floor((static_cast<float>(sw) - vw) * 0.5F); vx = std::floor((static_cast<float>(sw) - vw) * 0.5F);
vy = std::floor((static_cast<float>(sh) - vh) * 0.5F); vy = std::floor((static_cast<float>(sh) - vh) * 0.5F);
SDL_GPUViewport vp = {vx, vy, vw, vh, 0.0F, 1.0F}; SDL_GPUViewport vp = {.x = vx, .y = vy, .w = vw, .h = vh, .min_depth = 0.0F, .max_depth = 1.0F};
SDL_SetGPUViewport(pass, &vp); SDL_SetGPUViewport(pass, &vp);
// pixel_scale: pixels físicos por pixel lógico de juego (para scanlines sin SS). // pixel_scale: subpíxeles de textura por pixel lógico de juego.
// Con SS las scanlines están horneadas en CPU → scanline_strength=0 → no se usa. // Sin SS: vh/game_height (zoom de ventana).
uniforms_.pixel_scale = (game_height_ > 0) // Con SS: ss_factor_ exacto (3, 6, 9...) — la textura scaled tiene exactamente
? (vh / static_cast<float>(game_height_)) // ss_factor_ subfilas por fila lógica, múltiplo de 3 garantizado.
uniforms_.pixel_scale = (oversample_ > 1 && ss_factor_ > 0)
? static_cast<float>(ss_factor_)
: ((game_height_ > 0) ? (vh / static_cast<float>(game_height_)) : 1.0F);
uniforms_.time = static_cast<float>(SDL_GetTicks()) / 1000.0F;
uniforms_.oversample = (oversample_ > 1 && ss_factor_ > 0)
? static_cast<float>(ss_factor_)
: 1.0F; : 1.0F;
uniforms_.time = static_cast<float>(SDL_GetTicks()) / 1000.0F;
uniforms_.oversample = static_cast<float>(oversample_);
// Con supersampling usamos LINEAR para que el escalado a zooms no-múltiplo-de-3 // Con SS: leer de scaled_texture_ (ya ampliada); con LINEAR para suavizar
// promedia correctamente las filas de scanline horneadas en CPU. // el escalado final a zooms no-múltiplo-de-OS.
// Sin SS: leer de scene_texture_ con NEAREST.
SDL_GPUTexture* input_texture = (oversample_ > 1 && scaled_texture_ != nullptr)
? scaled_texture_
: scene_texture_;
SDL_GPUSampler* active_sampler = (oversample_ > 1 && linear_sampler_ != nullptr) SDL_GPUSampler* active_sampler = (oversample_ > 1 && linear_sampler_ != nullptr)
? linear_sampler_ : sampler_; ? linear_sampler_
: sampler_;
SDL_GPUTextureSamplerBinding binding = {}; SDL_GPUTextureSamplerBinding binding = {};
binding.texture = scene_texture_; binding.texture = input_texture;
binding.sampler = active_sampler; binding.sampler = active_sampler;
SDL_BindGPUFragmentSamplers(pass, 0, &binding, 1); SDL_BindGPUFragmentSamplers(pass, 0, &binding, 1);
@@ -538,10 +606,19 @@ namespace Rendering {
SDL_ReleaseGPUGraphicsPipeline(device_, pipeline_); SDL_ReleaseGPUGraphicsPipeline(device_, pipeline_);
pipeline_ = nullptr; pipeline_ = nullptr;
} }
if (upscale_pipeline_ != nullptr) {
SDL_ReleaseGPUGraphicsPipeline(device_, upscale_pipeline_);
upscale_pipeline_ = nullptr;
}
if (scene_texture_ != nullptr) { if (scene_texture_ != nullptr) {
SDL_ReleaseGPUTexture(device_, scene_texture_); SDL_ReleaseGPUTexture(device_, scene_texture_);
scene_texture_ = nullptr; scene_texture_ = nullptr;
} }
if (scaled_texture_ != nullptr) {
SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr;
}
ss_factor_ = 0;
if (upload_buffer_ != nullptr) { if (upload_buffer_ != nullptr) {
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_); SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
upload_buffer_ = nullptr; upload_buffer_ = nullptr;
@@ -598,7 +675,7 @@ namespace Rendering {
return shader; return shader;
} }
auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device, auto SDL3GPUShader::createShaderSPIRV(SDL_GPUDevice* device, // NOLINT(readability-convert-member-functions-to-static)
const uint8_t* spv_code, const uint8_t* spv_code,
size_t spv_size, size_t spv_size,
const char* entrypoint, const char* entrypoint,
@@ -622,16 +699,15 @@ namespace Rendering {
void SDL3GPUShader::setPostFXParams(const PostFXParams& p) { void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
uniforms_.vignette_strength = p.vignette; uniforms_.vignette_strength = p.vignette;
uniforms_.chroma_strength = p.chroma; uniforms_.chroma_strength = p.chroma;
uniforms_.mask_strength = p.mask; uniforms_.mask_strength = p.mask;
uniforms_.gamma_strength = p.gamma; uniforms_.gamma_strength = p.gamma;
uniforms_.curvature = p.curvature; uniforms_.curvature = p.curvature;
uniforms_.bleeding = p.bleeding; uniforms_.bleeding = p.bleeding;
uniforms_.flicker = p.flicker;
// Con supersampling las scanlines se hornean en CPU (uploadPixels). // Las scanlines siempre las aplica el shader PostFX en GPU.
// El shader recibe strength=0 para no aplicarlas de nuevo en GPU. uniforms_.scanline_strength = p.scanlines;
baked_scanline_strength_ = p.scanlines;
uniforms_.scanline_strength = (oversample_ > 1) ? 0.0F : p.scanlines;
} }
void SDL3GPUShader::setVSync(bool vsync) { void SDL3GPUShader::setVSync(bool vsync) {
@@ -659,8 +735,8 @@ namespace Rendering {
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// reinitTexturesAndBuffer — recrea scene_texture_ y upload_buffer_ con el // reinitTexturesAndBuffer — recrea scene_texture_, scaled_texture_ y
// tamaño actual (game × oversample_). No toca pipeline ni samplers. // upload_buffer_ con el factor oversample_ actual. No toca pipelines ni samplers.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
auto SDL3GPUShader::reinitTexturesAndBuffer() -> bool { auto SDL3GPUShader::reinitTexturesAndBuffer() -> bool {
if (device_ == nullptr) { return false; } if (device_ == nullptr) { return false; }
@@ -670,22 +746,28 @@ namespace Rendering {
SDL_ReleaseGPUTexture(device_, scene_texture_); SDL_ReleaseGPUTexture(device_, scene_texture_);
scene_texture_ = nullptr; scene_texture_ = nullptr;
} }
// scaled_texture_ se libera aquí; se recreará en el primer render() con el factor correcto
if (scaled_texture_ != nullptr) {
SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr;
}
ss_factor_ = 0;
if (upload_buffer_ != nullptr) { if (upload_buffer_ != nullptr) {
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_); SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
upload_buffer_ = nullptr; upload_buffer_ = nullptr;
} }
tex_width_ = game_width_ * oversample_; uniforms_.screen_height = static_cast<float>(game_height_);
tex_height_ = game_height_ * oversample_; uniforms_.oversample = static_cast<float>(oversample_);
uniforms_.screen_height = static_cast<float>(tex_height_);
uniforms_.oversample = static_cast<float>(oversample_);
// scene_texture_: siempre a resolución del juego
SDL_GPUTextureCreateInfo tex_info = {}; SDL_GPUTextureCreateInfo tex_info = {};
tex_info.type = SDL_GPU_TEXTURETYPE_2D; tex_info.type = SDL_GPU_TEXTURETYPE_2D;
tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM; tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
tex_info.width = static_cast<Uint32>(tex_width_); tex_info.width = static_cast<Uint32>(game_width_);
tex_info.height = static_cast<Uint32>(tex_height_); tex_info.height = static_cast<Uint32>(game_height_);
tex_info.layer_count_or_depth = 1; tex_info.layer_count_or_depth = 1;
tex_info.num_levels = 1; tex_info.num_levels = 1;
scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info); scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info);
@@ -694,9 +776,10 @@ namespace Rendering {
return false; return false;
} }
// upload_buffer_: siempre a resolución del juego
SDL_GPUTransferBufferCreateInfo tb_info = {}; SDL_GPUTransferBufferCreateInfo tb_info = {};
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
tb_info.size = static_cast<Uint32>(tex_width_ * tex_height_ * 4); tb_info.size = static_cast<Uint32>(game_width_ * game_height_ * 4);
upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info); upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info);
if (upload_buffer_ == nullptr) { if (upload_buffer_ == nullptr) {
SDL_Log("SDL3GPUShader: reinit — failed to create upload buffer: %s", SDL_GetError()); SDL_Log("SDL3GPUShader: reinit — failed to create upload buffer: %s", SDL_GetError());
@@ -705,7 +788,56 @@ namespace Rendering {
return false; return false;
} }
SDL_Log("SDL3GPUShader: oversample %d → texture %dx%d", oversample_, tex_width_, tex_height_); SDL_Log("SDL3GPUShader: reinit — scene %dx%d, SS %s (scaled se creará en render)",
game_width_,
game_height_,
oversample_ > 1 ? "on" : "off");
return true;
}
// ---------------------------------------------------------------------------
// calcSsFactor — primer múltiplo de 3 >= zoom, mínimo 3.
// Ejemplos: zoom 1,2,3 → 3; zoom 4,5,6 → 6; zoom 4.4 → 6; zoom 7,8,9 → 9.
// ---------------------------------------------------------------------------
auto SDL3GPUShader::calcSsFactor(float zoom) -> int {
const int MULTIPLE = 3;
const int n = static_cast<int>(std::ceil(zoom / static_cast<float>(MULTIPLE)));
return std::max(1, n) * MULTIPLE;
}
// ---------------------------------------------------------------------------
// recreateScaledTexture — libera y recrea scaled_texture_ para el factor dado.
// Llamar solo cuando device_ no esté ejecutando comandos (SDL_WaitForGPUIdle previo).
// ---------------------------------------------------------------------------
auto SDL3GPUShader::recreateScaledTexture(int factor) -> bool {
if (scaled_texture_ != nullptr) {
SDL_ReleaseGPUTexture(device_, scaled_texture_);
scaled_texture_ = nullptr;
}
ss_factor_ = 0;
const int W = game_width_ * factor;
const int H = game_height_ * factor;
SDL_GPUTextureCreateInfo info = {};
info.type = SDL_GPU_TEXTURETYPE_2D;
info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
info.width = static_cast<Uint32>(W);
info.height = static_cast<Uint32>(H);
info.layer_count_or_depth = 1;
info.num_levels = 1;
scaled_texture_ = SDL_CreateGPUTexture(device_, &info);
if (scaled_texture_ == nullptr) {
SDL_Log("SDL3GPUShader: failed to create scaled texture %dx%d (factor %d): %s",
W,
H,
factor,
SDL_GetError());
return false;
}
ss_factor_ = factor;
SDL_Log("SDL3GPUShader: scaled texture %dx%d (factor %d×)", W, H, factor);
return true; return true;
} }

View File

@@ -20,7 +20,7 @@ struct PostFXUniforms {
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_) float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f) float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f)
float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS) float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS)
float pad1; // padding — keep struct at 48 bytes (3 × 16) float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz — keep struct at 48 bytes (3 × 16)
}; };
namespace Rendering { namespace Rendering {
@@ -47,6 +47,7 @@ namespace Rendering {
void cleanup() final; // Libera pipeline/texturas pero mantiene el device vivo void cleanup() final; // Libera pipeline/texturas pero mantiene el device vivo
void destroy(); // Limpieza completa (device + swapchain); llamar solo al cerrar void destroy(); // Limpieza completa (device + swapchain); llamar solo al cerrar
[[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; } [[nodiscard]] auto isHardwareAccelerated() const -> bool override { return is_initialized_; }
[[nodiscard]] auto getDriverName() const -> std::string override { return driver_name_; }
// Sube píxeles ARGB8888 desde CPU; llamado antes de render() // Sube píxeles ARGB8888 desde CPU; llamado antes de render()
void uploadPixels(const Uint32* pixels, int width, int height) override; void uploadPixels(const Uint32* pixels, int width, int height) override;
@@ -80,24 +81,27 @@ namespace Rendering {
Uint32 num_uniform_buffers) -> SDL_GPUShader*; Uint32 num_uniform_buffers) -> SDL_GPUShader*;
auto createPipeline() -> bool; auto createPipeline() -> bool;
auto reinitTexturesAndBuffer() -> bool; // Recrea textura y buffer con oversample actual auto reinitTexturesAndBuffer() -> bool; // Recrea scene_texture_ y upload_buffer_
auto recreateScaledTexture(int factor) -> bool; // Recrea scaled_texture_ para factor dado
static auto calcSsFactor(float zoom) -> int; // Primer múltiplo de 3 >= zoom (mín 3)
SDL_Window* window_ = nullptr; SDL_Window* window_ = nullptr;
SDL_GPUDevice* device_ = nullptr; SDL_GPUDevice* device_ = nullptr;
SDL_GPUGraphicsPipeline* pipeline_ = nullptr; SDL_GPUGraphicsPipeline* pipeline_ = nullptr; // PostFX pass
SDL_GPUTexture* scene_texture_ = nullptr; SDL_GPUGraphicsPipeline* upscale_pipeline_ = nullptr; // Upscale nearest pass (solo con SS)
SDL_GPUTexture* scene_texture_ = nullptr; // Canvas del juego (game_width_ × game_height_)
SDL_GPUTexture* scaled_texture_ = nullptr; // Render target intermedio (win*SS × win*SS), solo con SS
SDL_GPUTransferBuffer* upload_buffer_ = nullptr; SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
SDL_GPUSampler* sampler_ = nullptr; // NEAREST — para path sin supersampling SDL_GPUSampler* sampler_ = nullptr; // NEAREST
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR — para path con supersampling SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F}; PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F};
int game_width_ = 0; // Dimensiones originales del canvas (sin SS) int game_width_ = 0; // Dimensiones originales del canvas
int game_height_ = 0; int game_height_ = 0;
int tex_width_ = 0; // Dimensiones de la textura GPU (game × oversample_) int ss_factor_ = 0; // Factor SS activo (3, 6, 9...) o 0 si SS desactivado
int tex_height_ = 0; int oversample_ = 1; // SS on/off (1 = off, >1 = on)
int oversample_ = 1; // Factor SS actual (1 o 3) std::string driver_name_;
float baked_scanline_strength_ = 0.0F; // Guardado para hornear en CPU
bool is_initialized_ = false; bool is_initialized_ = false;
bool vsync_ = true; bool vsync_ = true;
bool integer_scale_ = false; bool integer_scale_ = false;

View File

@@ -0,0 +1,634 @@
#pragma once
#include <cstddef>
#include <cstdint>
static const uint8_t kupscale_frag_spv[] = {
0x03,
0x02,
0x23,
0x07,
0x00,
0x00,
0x01,
0x00,
0x0b,
0x00,
0x0d,
0x00,
0x14,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x11,
0x00,
0x02,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0b,
0x00,
0x06,
0x00,
0x01,
0x00,
0x00,
0x00,
0x47,
0x4c,
0x53,
0x4c,
0x2e,
0x73,
0x74,
0x64,
0x2e,
0x34,
0x35,
0x30,
0x00,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x03,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0f,
0x00,
0x07,
0x00,
0x04,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x6d,
0x61,
0x69,
0x6e,
0x00,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x10,
0x00,
0x03,
0x00,
0x04,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x00,
0x03,
0x00,
0x03,
0x00,
0x02,
0x00,
0x00,
0x00,
0xc2,
0x01,
0x00,
0x00,
0x04,
0x00,
0x0a,
0x00,
0x47,
0x4c,
0x5f,
0x47,
0x4f,
0x4f,
0x47,
0x4c,
0x45,
0x5f,
0x63,
0x70,
0x70,
0x5f,
0x73,
0x74,
0x79,
0x6c,
0x65,
0x5f,
0x6c,
0x69,
0x6e,
0x65,
0x5f,
0x64,
0x69,
0x72,
0x65,
0x63,
0x74,
0x69,
0x76,
0x65,
0x00,
0x00,
0x04,
0x00,
0x08,
0x00,
0x47,
0x4c,
0x5f,
0x47,
0x4f,
0x4f,
0x47,
0x4c,
0x45,
0x5f,
0x69,
0x6e,
0x63,
0x6c,
0x75,
0x64,
0x65,
0x5f,
0x64,
0x69,
0x72,
0x65,
0x63,
0x74,
0x69,
0x76,
0x65,
0x00,
0x05,
0x00,
0x04,
0x00,
0x04,
0x00,
0x00,
0x00,
0x6d,
0x61,
0x69,
0x6e,
0x00,
0x00,
0x00,
0x00,
0x05,
0x00,
0x05,
0x00,
0x09,
0x00,
0x00,
0x00,
0x6f,
0x75,
0x74,
0x5f,
0x63,
0x6f,
0x6c,
0x6f,
0x72,
0x00,
0x00,
0x00,
0x05,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x73,
0x63,
0x65,
0x6e,
0x65,
0x00,
0x00,
0x00,
0x05,
0x00,
0x04,
0x00,
0x11,
0x00,
0x00,
0x00,
0x76,
0x5f,
0x75,
0x76,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x09,
0x00,
0x00,
0x00,
0x1e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x21,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x22,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x47,
0x00,
0x04,
0x00,
0x11,
0x00,
0x00,
0x00,
0x1e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x13,
0x00,
0x02,
0x00,
0x02,
0x00,
0x00,
0x00,
0x21,
0x00,
0x03,
0x00,
0x03,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x16,
0x00,
0x03,
0x00,
0x06,
0x00,
0x00,
0x00,
0x20,
0x00,
0x00,
0x00,
0x17,
0x00,
0x04,
0x00,
0x07,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x08,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x08,
0x00,
0x00,
0x00,
0x09,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0x19,
0x00,
0x09,
0x00,
0x0a,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x1b,
0x00,
0x03,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x0a,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x0c,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x0c,
0x00,
0x00,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x17,
0x00,
0x04,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x06,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x00,
0x20,
0x00,
0x04,
0x00,
0x10,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x3b,
0x00,
0x04,
0x00,
0x10,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x36,
0x00,
0x05,
0x00,
0x02,
0x00,
0x00,
0x00,
0x04,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x03,
0x00,
0x00,
0x00,
0xf8,
0x00,
0x02,
0x00,
0x05,
0x00,
0x00,
0x00,
0x3d,
0x00,
0x04,
0x00,
0x0b,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x00,
0x00,
0x0d,
0x00,
0x00,
0x00,
0x3d,
0x00,
0x04,
0x00,
0x0f,
0x00,
0x00,
0x00,
0x12,
0x00,
0x00,
0x00,
0x11,
0x00,
0x00,
0x00,
0x57,
0x00,
0x05,
0x00,
0x07,
0x00,
0x00,
0x00,
0x13,
0x00,
0x00,
0x00,
0x0e,
0x00,
0x00,
0x00,
0x12,
0x00,
0x00,
0x00,
0x3e,
0x00,
0x03,
0x00,
0x09,
0x00,
0x00,
0x00,
0x13,
0x00,
0x00,
0x00,
0xfd,
0x00,
0x01,
0x00,
0x38,
0x00,
0x01,
0x00,
};
static const size_t kupscale_frag_spv_size = 628;

View File

@@ -11,13 +11,14 @@ namespace Rendering {
* Definido a nivel de namespace para facilitar el uso desde subclases y screen.cpp * Definido a nivel de namespace para facilitar el uso desde subclases y screen.cpp
*/ */
struct PostFXParams { struct PostFXParams {
float vignette = 0.0F; // Intensidad de la viñeta float vignette = 0.0F; // Intensidad de la viñeta
float scanlines = 0.0F; // Intensidad de las scanlines float scanlines = 0.0F; // Intensidad de las scanlines
float chroma = 0.0F; // Aberración cromática float chroma = 0.0F; // Aberración cromática
float mask = 0.0F; // Máscara de fósforo RGB float mask = 0.0F; // Máscara de fósforo RGB
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full) float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
float curvature = 0.0F; // Curvatura barrel CRT float curvature = 0.0F; // Curvatura barrel CRT
float bleeding = 0.0F; // Sangrado de color NTSC float bleeding = 0.0F; // Sangrado de color NTSC
float flicker = 0.0F; // Parpadeo de fósforo CRT ~50 Hz
}; };
/** /**
@@ -94,6 +95,12 @@ namespace Rendering {
* @return true si usa aceleración (OpenGL/Metal/Vulkan) * @return true si usa aceleración (OpenGL/Metal/Vulkan)
*/ */
[[nodiscard]] virtual auto isHardwareAccelerated() const -> bool = 0; [[nodiscard]] virtual auto isHardwareAccelerated() const -> bool = 0;
/**
* @brief Nombre del driver GPU activo (p.ej. "vulkan", "metal", "direct3d12")
* @return Cadena vacía si no disponible
*/
[[nodiscard]] virtual auto getDriverName() const -> std::string { return {}; }
}; };
} // namespace Rendering } // namespace Rendering

View File

@@ -1,4 +1,4 @@
#include "core/rendering/surface_animated_sprite.hpp" #include "core/rendering/sprite/animated_sprite.hpp"
#include <cstddef> // Para size_t #include <cstddef> // Para size_t
#include <fstream> // Para basic_ostream, basic_istream, operator<<, basic... #include <fstream> // Para basic_ostream, basic_istream, operator<<, basic...
@@ -16,7 +16,7 @@
// Helper: Convierte un nodo YAML de frames (array) a vector de SDL_FRect // Helper: Convierte un nodo YAML de frames (array) a vector de SDL_FRect
auto convertYAMLFramesToRects(const fkyaml::node& frames_node, float frame_width, float frame_height, int frames_per_row, int max_tiles) -> std::vector<SDL_FRect> { auto convertYAMLFramesToRects(const fkyaml::node& frames_node, float frame_width, float frame_height, int frames_per_row, int max_tiles) -> std::vector<SDL_FRect> {
std::vector<SDL_FRect> frames; std::vector<SDL_FRect> frames;
SDL_FRect rect = {0.0F, 0.0F, frame_width, frame_height}; SDL_FRect rect = {.x = 0.0F, .y = 0.0F, .w = frame_width, .h = frame_height};
for (const auto& frame_index_node : frames_node) { for (const auto& frame_index_node : frames_node) {
const int NUM_TILE = frame_index_node.get_value<int>(); const int NUM_TILE = frame_index_node.get_value<int>();
@@ -31,7 +31,7 @@ auto convertYAMLFramesToRects(const fkyaml::node& frames_node, float frame_width
} }
// Carga las animaciones desde un fichero YAML // Carga las animaciones desde un fichero YAML
auto SurfaceAnimatedSprite::loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData> { auto AnimatedSprite::loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData> { // NOLINT(readability-convert-member-functions-to-static)
std::vector<AnimationData> animations; std::vector<AnimationData> animations;
// Extract filename for logging // Extract filename for logging
@@ -124,7 +124,7 @@ auto SurfaceAnimatedSprite::loadAnimationsFromYAML(const std::string& file_path,
} }
// Constructor con bytes YAML del cache (parsing lazy) // Constructor con bytes YAML del cache (parsing lazy)
SurfaceAnimatedSprite::SurfaceAnimatedSprite(const AnimationResource& cached_data) { AnimatedSprite::AnimatedSprite(const AnimationResource& cached_data) {
// Parsear YAML desde los bytes cargados en cache // Parsear YAML desde los bytes cargados en cache
std::string yaml_content(cached_data.yaml_data.begin(), cached_data.yaml_data.end()); std::string yaml_content(cached_data.yaml_data.begin(), cached_data.yaml_data.end());
@@ -215,8 +215,8 @@ SurfaceAnimatedSprite::SurfaceAnimatedSprite(const AnimationResource& cached_dat
} }
// Constructor per a subclasses amb surface directa (sense YAML) // Constructor per a subclasses amb surface directa (sense YAML)
SurfaceAnimatedSprite::SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos) AnimatedSprite::AnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
: SurfaceMovingSprite(std::move(surface), pos) { : MovingSprite(std::move(surface), pos) {
// animations_ queda buit (protegit per el guard de animate()) // animations_ queda buit (protegit per el guard de animate())
if (surface_) { if (surface_) {
clip_ = {.x = 0, .y = 0, .w = surface_->getWidth(), .h = surface_->getHeight()}; clip_ = {.x = 0, .y = 0, .w = surface_->getWidth(), .h = surface_->getHeight()};
@@ -224,7 +224,7 @@ SurfaceAnimatedSprite::SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, S
} }
// Obtiene el indice de la animación a partir del nombre // Obtiene el indice de la animación a partir del nombre
auto SurfaceAnimatedSprite::getIndex(const std::string& name) -> int { auto AnimatedSprite::getIndex(const std::string& name) -> int { // NOLINT(readability-convert-member-functions-to-static)
auto index = -1; auto index = -1;
for (const auto& a : animations_) { for (const auto& a : animations_) {
@@ -238,7 +238,7 @@ auto SurfaceAnimatedSprite::getIndex(const std::string& name) -> int {
} }
// Calcula el frame correspondiente a la animación (time-based) // Calcula el frame correspondiente a la animación (time-based)
void SurfaceAnimatedSprite::animate(float delta_time) { void AnimatedSprite::animate(float delta_time) { // NOLINT(readability-convert-member-functions-to-static)
if (animations_.empty()) { return; } if (animations_.empty()) { return; }
if (animations_[current_animation_].speed <= 0.0F) { if (animations_[current_animation_].speed <= 0.0F) {
return; return;
@@ -288,12 +288,12 @@ void SurfaceAnimatedSprite::animate(float delta_time) {
} }
// Comprueba si ha terminado la animación // Comprueba si ha terminado la animación
auto SurfaceAnimatedSprite::animationIsCompleted() -> bool { auto AnimatedSprite::animationIsCompleted() -> bool {
return animations_[current_animation_].completed; return animations_[current_animation_].completed;
} }
// Establece la animacion actual // Establece la animacion actual
void SurfaceAnimatedSprite::setCurrentAnimation(const std::string& name) { void AnimatedSprite::setCurrentAnimation(const std::string& name) {
const auto NEW_ANIMATION = getIndex(name); const auto NEW_ANIMATION = getIndex(name);
if (current_animation_ != NEW_ANIMATION) { if (current_animation_ != NEW_ANIMATION) {
current_animation_ = NEW_ANIMATION; current_animation_ = NEW_ANIMATION;
@@ -305,7 +305,7 @@ void SurfaceAnimatedSprite::setCurrentAnimation(const std::string& name) {
} }
// Establece la animacion actual // Establece la animacion actual
void SurfaceAnimatedSprite::setCurrentAnimation(int index) { void AnimatedSprite::setCurrentAnimation(int index) {
const auto NEW_ANIMATION = index; const auto NEW_ANIMATION = index;
if (current_animation_ != NEW_ANIMATION) { if (current_animation_ != NEW_ANIMATION) {
current_animation_ = NEW_ANIMATION; current_animation_ = NEW_ANIMATION;
@@ -317,20 +317,20 @@ void SurfaceAnimatedSprite::setCurrentAnimation(int index) {
} }
// Actualiza las variables del objeto (time-based) // Actualiza las variables del objeto (time-based)
void SurfaceAnimatedSprite::update(float delta_time) { void AnimatedSprite::update(float delta_time) {
animate(delta_time); animate(delta_time);
SurfaceMovingSprite::update(delta_time); MovingSprite::update(delta_time);
} }
// Reinicia la animación // Reinicia la animación
void SurfaceAnimatedSprite::resetAnimation() { void AnimatedSprite::resetAnimation() {
animations_[current_animation_].current_frame = 0; animations_[current_animation_].current_frame = 0;
animations_[current_animation_].accumulated_time = 0.0F; animations_[current_animation_].accumulated_time = 0.0F;
animations_[current_animation_].completed = false; animations_[current_animation_].completed = false;
} }
// Establece el frame actual de la animación // Establece el frame actual de la animación
void SurfaceAnimatedSprite::setCurrentAnimationFrame(int num) { void AnimatedSprite::setCurrentAnimationFrame(int num) {
// Descarta valores fuera de rango // Descarta valores fuera de rango
if (num < 0 || num >= static_cast<int>(animations_[current_animation_].frames.size())) { if (num < 0 || num >= static_cast<int>(animations_[current_animation_].frames.size())) {
num = 0; num = 0;

View File

@@ -7,12 +7,12 @@
#include <utility> #include <utility>
#include <vector> // Para vector #include <vector> // Para vector
#include "core/rendering/surface_moving_sprite.hpp" // Para SMovingSprite #include "core/rendering/sprite/moving_sprite.hpp" // Para SMovingSprite
#include "core/resources/resource_types.hpp" // Para AnimationResource #include "core/resources/resource_types.hpp" // Para AnimationResource
class Surface; class Surface;
class SurfaceAnimatedSprite : public SurfaceMovingSprite { class AnimatedSprite : public MovingSprite {
public: public:
using Animations = std::vector<std::string>; // Tipo para lista de animaciones using Animations = std::vector<std::string>; // Tipo para lista de animaciones
@@ -31,9 +31,9 @@ class SurfaceAnimatedSprite : public SurfaceMovingSprite {
static auto loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData>; // Carga las animaciones desde fichero YAML static auto loadAnimationsFromYAML(const std::string& file_path, std::shared_ptr<Surface>& surface, float& frame_width, float& frame_height) -> std::vector<AnimationData>; // Carga las animaciones desde fichero YAML
// Constructores // Constructores
explicit SurfaceAnimatedSprite(const AnimationResource& cached_data); // Constructor con datos pre-cargados del cache explicit AnimatedSprite(const AnimationResource& cached_data); // Constructor con datos pre-cargados del cache
~SurfaceAnimatedSprite() override = default; // Destructor ~AnimatedSprite() override = default; // Destructor
void update(float delta_time) override; // Actualiza las variables del objeto (time-based) void update(float delta_time) override; // Actualiza las variables del objeto (time-based)
@@ -50,7 +50,7 @@ class SurfaceAnimatedSprite : public SurfaceMovingSprite {
protected: protected:
// Constructor per a ús de subclasses que gestionen la surface directament (sense YAML) // Constructor per a ús de subclasses que gestionen la surface directament (sense YAML)
SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos); AnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
// Métodos protegidos // Métodos protegidos
void animate(float delta_time); // Calcula el frame correspondiente a la animación actual (time-based) void animate(float delta_time); // Calcula el frame correspondiente a la animación actual (time-based)

View File

@@ -1,4 +1,4 @@
#include "core/rendering/surface_dissolve_sprite.hpp" #include "core/rendering/sprite/dissolve_sprite.hpp"
#include <algorithm> // Para min #include <algorithm> // Para min
#include <cstdint> // Para uint32_t #include <cstdint> // Para uint32_t
@@ -15,7 +15,7 @@ static auto pixelRank(int col, int row) -> float {
} }
// Rang per a un píxel tenint en compte direcció (70% direccional + 30% aleatori) // Rang per a un píxel tenint en compte direcció (70% direccional + 30% aleatori)
auto SurfaceDissolveSprite::computePixelRank(int col, int row, int frame_h, DissolveDirection dir) -> float { auto DissolveSprite::computePixelRank(int col, int row, int frame_h, DissolveDirection dir) -> float {
const float RANDOM = pixelRank(col, row); const float RANDOM = pixelRank(col, row);
if (dir == DissolveDirection::NONE || frame_h <= 0) { if (dir == DissolveDirection::NONE || frame_h <= 0) {
return RANDOM; return RANDOM;
@@ -32,8 +32,8 @@ auto SurfaceDissolveSprite::computePixelRank(int col, int row, int frame_h, Diss
} }
// Constructor per a surface directa (sense AnimationResource) // Constructor per a surface directa (sense AnimationResource)
SurfaceDissolveSprite::SurfaceDissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos) DissolveSprite::DissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
: SurfaceAnimatedSprite(std::move(surface), pos) { : AnimatedSprite(std::move(surface), pos) {
if (surface_) { if (surface_) {
const int W = static_cast<int>(surface_->getWidth()); const int W = static_cast<int>(surface_->getWidth());
const int H = static_cast<int>(surface_->getHeight()); const int H = static_cast<int>(surface_->getHeight());
@@ -44,8 +44,8 @@ SurfaceDissolveSprite::SurfaceDissolveSprite(std::shared_ptr<Surface> surface, S
} }
// Constructor // Constructor
SurfaceDissolveSprite::SurfaceDissolveSprite(const AnimationResource& data) DissolveSprite::DissolveSprite(const AnimationResource& data)
: SurfaceAnimatedSprite(data) { : AnimatedSprite(data) {
if (surface_) { if (surface_) {
const int W = static_cast<int>(surface_->getWidth()); const int W = static_cast<int>(surface_->getWidth());
const int H = static_cast<int>(surface_->getHeight()); const int H = static_cast<int>(surface_->getHeight());
@@ -57,7 +57,7 @@ SurfaceDissolveSprite::SurfaceDissolveSprite(const AnimationResource& data)
} }
// Reconstrueix la surface_display_ filtrant píxels per progress_ // Reconstrueix la surface_display_ filtrant píxels per progress_
void SurfaceDissolveSprite::rebuildDisplaySurface() { void DissolveSprite::rebuildDisplaySurface() {
if (!surface_ || !surface_display_) { if (!surface_ || !surface_display_) {
return; return;
} }
@@ -109,9 +109,9 @@ void SurfaceDissolveSprite::rebuildDisplaySurface() {
} }
// Actualitza animació, moviment i transició temporal // Actualitza animació, moviment i transició temporal
void SurfaceDissolveSprite::update(float delta_time) { void DissolveSprite::update(float delta_time) {
const SDL_FRect OLD_CLIP = clip_; const SDL_FRect OLD_CLIP = clip_;
SurfaceAnimatedSprite::update(delta_time); AnimatedSprite::update(delta_time);
// Detecta canvi de frame d'animació // Detecta canvi de frame d'animació
if (clip_.x != OLD_CLIP.x || clip_.y != OLD_CLIP.y || if (clip_.x != OLD_CLIP.x || clip_.y != OLD_CLIP.y ||
@@ -136,22 +136,22 @@ void SurfaceDissolveSprite::update(float delta_time) {
} }
// Renderitza: usa surface_display_ (amb color replace) si disponible // Renderitza: usa surface_display_ (amb color replace) si disponible
void SurfaceDissolveSprite::render() { void DissolveSprite::render() {
if (!surface_display_) { if (!surface_display_) {
SurfaceAnimatedSprite::render(); AnimatedSprite::render();
return; return;
} }
surface_display_->render(static_cast<int>(pos_.x), static_cast<int>(pos_.y), &clip_, flip_); surface_display_->render(static_cast<int>(pos_.x), static_cast<int>(pos_.y), &clip_, flip_);
} }
// Estableix el progrés manualment // Estableix el progrés manualment
void SurfaceDissolveSprite::setProgress(float progress) { void DissolveSprite::setProgress(float progress) {
progress_ = std::min(std::max(progress, 0.0F), 1.0F); progress_ = std::min(std::max(progress, 0.0F), 1.0F);
needs_rebuild_ = true; needs_rebuild_ = true;
} }
// Inicia dissolució temporal (visible → invisible) // Inicia dissolució temporal (visible → invisible)
void SurfaceDissolveSprite::startDissolve(float duration_ms, DissolveDirection dir) { void DissolveSprite::startDissolve(float duration_ms, DissolveDirection dir) {
direction_ = dir; direction_ = dir;
transition_mode_ = TransitionMode::DISSOLVING; transition_mode_ = TransitionMode::DISSOLVING;
transition_duration_ = duration_ms; transition_duration_ = duration_ms;
@@ -161,7 +161,7 @@ void SurfaceDissolveSprite::startDissolve(float duration_ms, DissolveDirection d
} }
// Inicia generació temporal (invisible → visible) // Inicia generació temporal (invisible → visible)
void SurfaceDissolveSprite::startGenerate(float duration_ms, DissolveDirection dir) { void DissolveSprite::startGenerate(float duration_ms, DissolveDirection dir) {
direction_ = dir; direction_ = dir;
transition_mode_ = TransitionMode::GENERATING; transition_mode_ = TransitionMode::GENERATING;
transition_duration_ = duration_ms; transition_duration_ = duration_ms;
@@ -171,17 +171,17 @@ void SurfaceDissolveSprite::startGenerate(float duration_ms, DissolveDirection d
} }
// Atura la transició temporal // Atura la transició temporal
void SurfaceDissolveSprite::stopTransition() { void DissolveSprite::stopTransition() {
transition_mode_ = TransitionMode::NONE; transition_mode_ = TransitionMode::NONE;
} }
// Retorna si la transició ha acabat // Retorna si la transició ha acabat
auto SurfaceDissolveSprite::isTransitionDone() const -> bool { auto DissolveSprite::isTransitionDone() const -> bool {
return transition_mode_ == TransitionMode::NONE; return transition_mode_ == TransitionMode::NONE;
} }
// Configura substitució de color per a la reconstrucció // Configura substitució de color per a la reconstrucció
void SurfaceDissolveSprite::setColorReplace(Uint8 source, Uint8 target) { void DissolveSprite::setColorReplace(Uint8 source, Uint8 target) {
source_color_ = source; source_color_ = source;
target_color_ = target; target_color_ = target;
needs_rebuild_ = true; needs_rebuild_ = true;

View File

@@ -4,7 +4,7 @@
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include "core/rendering/surface_animated_sprite.hpp" // Para SurfaceAnimatedSprite #include "core/rendering/sprite/animated_sprite.hpp" // Para SurfaceAnimatedSprite
class Surface; class Surface;
@@ -15,11 +15,11 @@ enum class DissolveDirection { NONE,
// Sprite que pot dissoldre's o generar-se de forma aleatòria en X mil·lisegons. // Sprite que pot dissoldre's o generar-se de forma aleatòria en X mil·lisegons.
// progress_ va de 0.0 (totalment visible) a 1.0 (totalment invisible). // progress_ va de 0.0 (totalment visible) a 1.0 (totalment invisible).
class SurfaceDissolveSprite : public SurfaceAnimatedSprite { class DissolveSprite : public AnimatedSprite {
public: public:
explicit SurfaceDissolveSprite(const AnimationResource& data); explicit DissolveSprite(const AnimationResource& data);
SurfaceDissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos); DissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
~SurfaceDissolveSprite() override = default; ~DissolveSprite() override = default;
void update(float delta_time) override; void update(float delta_time) override;
void render() override; void render() override;
@@ -52,7 +52,7 @@ class SurfaceDissolveSprite : public SurfaceAnimatedSprite {
TransitionMode transition_mode_{TransitionMode::NONE}; TransitionMode transition_mode_{TransitionMode::NONE};
float transition_duration_{0.0F}; float transition_duration_{0.0F};
float transition_elapsed_{0.0F}; float transition_elapsed_{0.0F};
SDL_FRect prev_clip_{0, 0, 0, 0}; SDL_FRect prev_clip_{.x = 0, .y = 0, .w = 0, .h = 0};
bool needs_rebuild_{false}; bool needs_rebuild_{false};
Uint8 source_color_{255}; // 255 = transparent = sense replace per defecte Uint8 source_color_{255}; // 255 = transparent = sense replace per defecte
Uint8 target_color_{0}; Uint8 target_color_{0};

View File

@@ -1,28 +1,28 @@
#include "core/rendering/surface_moving_sprite.hpp" #include "core/rendering/sprite/moving_sprite.hpp"
#include <utility> #include <utility>
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/surface.hpp" // Para Surface
// Constructor // Constructor
SurfaceMovingSprite::SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip) MovingSprite::MovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip)
: SurfaceSprite(std::move(surface), pos), : Sprite(std::move(surface), pos),
x_(pos.x), x_(pos.x),
y_(pos.y), y_(pos.y),
flip_(flip) { SurfaceSprite::pos_ = pos; } flip_(flip) { Sprite::pos_ = pos; }
SurfaceMovingSprite::SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos) MovingSprite::MovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
: SurfaceSprite(std::move(surface), pos), : Sprite(std::move(surface), pos),
x_(pos.x), x_(pos.x),
y_(pos.y) { SurfaceSprite::pos_ = pos; } y_(pos.y) { Sprite::pos_ = pos; }
SurfaceMovingSprite::SurfaceMovingSprite() { SurfaceSprite::clear(); } MovingSprite::MovingSprite() { Sprite::clear(); }
SurfaceMovingSprite::SurfaceMovingSprite(std::shared_ptr<Surface> surface) MovingSprite::MovingSprite(std::shared_ptr<Surface> surface)
: SurfaceSprite(std::move(surface)) { SurfaceSprite::clear(); } : Sprite(std::move(surface)) { Sprite::clear(); }
// Reinicia todas las variables // Reinicia todas las variables
void SurfaceMovingSprite::clear() { void MovingSprite::clear() {
// Resetea posición // Resetea posición
x_ = 0.0F; x_ = 0.0F;
y_ = 0.0F; y_ = 0.0F;
@@ -38,13 +38,13 @@ void SurfaceMovingSprite::clear() {
// Resetea flip // Resetea flip
flip_ = SDL_FLIP_NONE; flip_ = SDL_FLIP_NONE;
SurfaceSprite::clear(); Sprite::clear();
} }
// Mueve el sprite (time-based) // Mueve el sprite (time-based)
// Nota: vx_, vy_ ahora se interpretan como pixels/segundo // Nota: vx_, vy_ ahora se interpretan como pixels/segundo
// Nota: ax_, ay_ ahora se interpretan como pixels/segundo² // Nota: ax_, ay_ ahora se interpretan como pixels/segundo²
void SurfaceMovingSprite::move(float delta_time) { void MovingSprite::move(float delta_time) {
// Aplica aceleración a velocidad (time-based) // Aplica aceleración a velocidad (time-based)
vx_ += ax_ * delta_time; vx_ += ax_ * delta_time;
vy_ += ay_ * delta_time; vy_ += ay_ * delta_time;
@@ -59,22 +59,22 @@ void SurfaceMovingSprite::move(float delta_time) {
} }
// Actualiza las variables internas del objeto (time-based) // Actualiza las variables internas del objeto (time-based)
void SurfaceMovingSprite::update(float delta_time) { void MovingSprite::update(float delta_time) {
move(delta_time); move(delta_time);
} }
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void SurfaceMovingSprite::render() { void MovingSprite::render() {
surface_->render(pos_.x, pos_.y, &clip_, flip_); surface_->render(pos_.x, pos_.y, &clip_, flip_);
} }
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void SurfaceMovingSprite::render(Uint8 source_color, Uint8 target_color) { void MovingSprite::render(Uint8 source_color, Uint8 target_color) {
surface_->renderWithColorReplace(pos_.x, pos_.y, source_color, target_color, &clip_, flip_); surface_->renderWithColorReplace(pos_.x, pos_.y, source_color, target_color, &clip_, flip_);
} }
// Establece la posición y_ el tamaño del objeto // Establece la posición y_ el tamaño del objeto
void SurfaceMovingSprite::setPos(SDL_FRect rect) { void MovingSprite::setPos(SDL_FRect rect) {
x_ = rect.x; x_ = rect.x;
y_ = rect.y; y_ = rect.y;
@@ -82,7 +82,7 @@ void SurfaceMovingSprite::setPos(SDL_FRect rect) {
} }
// Establece el valor de las variables // Establece el valor de las variables
void SurfaceMovingSprite::setPos(float x, float y) { void MovingSprite::setPos(float x, float y) {
x_ = x; x_ = x;
y_ = y; y_ = y;
@@ -91,13 +91,13 @@ void SurfaceMovingSprite::setPos(float x, float y) {
} }
// Establece el valor de la variable // Establece el valor de la variable
void SurfaceMovingSprite::setPosX(float value) { void MovingSprite::setPosX(float value) {
x_ = value; x_ = value;
pos_.x = static_cast<int>(x_); pos_.x = static_cast<int>(x_);
} }
// Establece el valor de la variable // Establece el valor de la variable
void SurfaceMovingSprite::setPosY(float value) { void MovingSprite::setPosY(float value) {
y_ = value; y_ = value;
pos_.y = static_cast<int>(y_); pos_.y = static_cast<int>(y_);
} }

View File

@@ -4,18 +4,18 @@
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include "core/rendering/surface_sprite.hpp" // Para SSprite #include "core/rendering/sprite/sprite.hpp" // Para SSprite
class Surface; // lines 8-8 class Surface; // lines 8-8
// Clase SMovingSprite. Añade movimiento y flip al sprite // Clase SMovingSprite. Añade movimiento y flip al sprite
class SurfaceMovingSprite : public SurfaceSprite { class MovingSprite : public Sprite {
public: public:
// Constructores // Constructores
SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip); MovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos, SDL_FlipMode flip);
SurfaceMovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos); MovingSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
explicit SurfaceMovingSprite(); explicit MovingSprite();
explicit SurfaceMovingSprite(std::shared_ptr<Surface> surface); explicit MovingSprite(std::shared_ptr<Surface> surface);
~SurfaceMovingSprite() override = default; ~MovingSprite() override = default;
// Actualización y renderizado // Actualización y renderizado
void update(float delta_time) override; // Actualiza variables internas (time-based) void update(float delta_time) override; // Actualiza variables internas (time-based)

View File

@@ -1,37 +1,37 @@
#include "core/rendering/surface_sprite.hpp" #include "core/rendering/sprite/sprite.hpp"
#include <utility> #include <utility>
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/surface.hpp" // Para Surface
// Constructor // Constructor
SurfaceSprite::SurfaceSprite(std::shared_ptr<Surface> surface, float x, float y, float w, float h) Sprite::Sprite(std::shared_ptr<Surface> surface, float x, float y, float w, float h)
: surface_(std::move(surface)), : surface_(std::move(surface)),
pos_{x, y, w, h}, pos_{.x = x, .y = y, .w = w, .h = h},
clip_{0.0F, 0.0F, pos_.w, pos_.h} {} clip_{.x = 0.0F, .y = 0.0F, .w = pos_.w, .h = pos_.h} {}
SurfaceSprite::SurfaceSprite(std::shared_ptr<Surface> surface, SDL_FRect rect) Sprite::Sprite(std::shared_ptr<Surface> surface, SDL_FRect rect)
: surface_(std::move(surface)), : surface_(std::move(surface)),
pos_(rect), pos_(rect),
clip_{0.0F, 0.0F, pos_.w, pos_.h} {} clip_{.x = 0.0F, .y = 0.0F, .w = pos_.w, .h = pos_.h} {}
SurfaceSprite::SurfaceSprite() = default; Sprite::Sprite() = default;
SurfaceSprite::SurfaceSprite(std::shared_ptr<Surface> surface) Sprite::Sprite(std::shared_ptr<Surface> surface)
: surface_(std::move(surface)), : surface_(std::move(surface)),
pos_{0.0F, 0.0F, surface_->getWidth(), surface_->getHeight()}, pos_{0.0F, 0.0F, surface_->getWidth(), surface_->getHeight()},
clip_(pos_) {} clip_(pos_) {}
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void SurfaceSprite::render() { void Sprite::render() {
surface_->render(pos_.x, pos_.y, &clip_); surface_->render(pos_.x, pos_.y, &clip_);
} }
void SurfaceSprite::render(Uint8 source_color, Uint8 target_color) { void Sprite::render(Uint8 source_color, Uint8 target_color) {
surface_->renderWithColorReplace(pos_.x, pos_.y, source_color, target_color, &clip_); surface_->renderWithColorReplace(pos_.x, pos_.y, source_color, target_color, &clip_);
} }
void SurfaceSprite::renderWithVerticalFade(int fade_h, int canvas_height) { void Sprite::renderWithVerticalFade(int fade_h, int canvas_height) {
surface_->renderWithVerticalFade( surface_->renderWithVerticalFade(
static_cast<int>(pos_.x), static_cast<int>(pos_.x),
static_cast<int>(pos_.y), static_cast<int>(pos_.y),
@@ -40,7 +40,7 @@ void SurfaceSprite::renderWithVerticalFade(int fade_h, int canvas_height) {
&clip_); &clip_);
} }
void SurfaceSprite::renderWithVerticalFade(int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color) { void Sprite::renderWithVerticalFade(int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color) {
surface_->renderWithVerticalFade( surface_->renderWithVerticalFade(
static_cast<int>(pos_.x), static_cast<int>(pos_.x),
static_cast<int>(pos_.y), static_cast<int>(pos_.y),
@@ -52,25 +52,25 @@ void SurfaceSprite::renderWithVerticalFade(int fade_h, int canvas_height, Uint8
} }
// Establece la posición del objeto // Establece la posición del objeto
void SurfaceSprite::setPosition(float x, float y) { void Sprite::setPosition(float x, float y) {
pos_.x = x; pos_.x = x;
pos_.y = y; pos_.y = y;
} }
// Establece la posición del objeto // Establece la posición del objeto
void SurfaceSprite::setPosition(SDL_FPoint p) { void Sprite::setPosition(SDL_FPoint p) {
pos_.x = p.x; pos_.x = p.x;
pos_.y = p.y; pos_.y = p.y;
} }
// Reinicia las variables a cero // Reinicia las variables a cero
void SurfaceSprite::clear() { void Sprite::clear() {
pos_ = {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; pos_ = {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F};
clip_ = {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; clip_ = {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F};
} }
// Actualiza el estado del sprite (time-based) // Actualiza el estado del sprite (time-based)
void SurfaceSprite::update(float delta_time) { void Sprite::update(float delta_time) {
// Base implementation does nothing (static sprites) // Base implementation does nothing (static sprites)
(void)delta_time; // Evita warning de parámetro no usado (void)delta_time; // Evita warning de parámetro no usado
} }

View File

@@ -7,16 +7,16 @@
class Surface; // lines 5-5 class Surface; // lines 5-5
// Clase SurfaceSprite // Clase SurfaceSprite
class SurfaceSprite { class Sprite {
public: public:
// Constructores // Constructores
SurfaceSprite(std::shared_ptr<Surface>, float x, float y, float w, float h); Sprite(std::shared_ptr<Surface>, float x, float y, float w, float h);
SurfaceSprite(std::shared_ptr<Surface>, SDL_FRect rect); Sprite(std::shared_ptr<Surface>, SDL_FRect rect);
SurfaceSprite(); Sprite();
explicit SurfaceSprite(std::shared_ptr<Surface>); explicit Sprite(std::shared_ptr<Surface>);
// Destructor // Destructor
virtual ~SurfaceSprite() = default; virtual ~Sprite() = default;
// Actualización y renderizado // Actualización y renderizado
virtual void update(float delta_time); // Actualiza el estado del sprite (time-based) virtual void update(float delta_time); // Actualiza el estado del sprite (time-based)
@@ -51,12 +51,12 @@ class SurfaceSprite {
// Modificación de clip y surface // Modificación de clip y surface
void setClip(SDL_FRect rect) { clip_ = rect; } void setClip(SDL_FRect rect) { clip_ = rect; }
void setClip(float x, float y, float w, float h) { clip_ = SDL_FRect{x, y, w, h}; } void setClip(float x, float y, float w, float h) { clip_ = SDL_FRect{.x = x, .y = y, .w = w, .h = h}; }
void setSurface(std::shared_ptr<Surface> surface) { surface_ = std::move(surface); } void setSurface(std::shared_ptr<Surface> surface) { surface_ = std::move(surface); }
protected: protected:
// Variables miembro // Variables miembro
std::shared_ptr<Surface> surface_{nullptr}; // Surface donde estan todos los dibujos del sprite std::shared_ptr<Surface> surface_{nullptr}; // Surface donde estan todos los dibujos del sprite
SDL_FRect pos_{0.0F, 0.0F, 0.0F, 0.0F}; // Posición y tamaño donde dibujar el sprite SDL_FRect pos_{.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; // Posición y tamaño donde dibujar el sprite
SDL_FRect clip_{0.0F, 0.0F, 0.0F, 0.0F}; // Rectangulo de origen de la surface que se dibujará en pantalla SDL_FRect clip_{.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; // Rectangulo de origen de la surface que se dibujará en pantalla
}; };

View File

@@ -104,7 +104,7 @@ Surface::Surface(const std::string& file_path)
} }
// Carga una superficie desde un archivo // Carga una superficie desde un archivo
auto Surface::loadSurface(const std::string& file_path) -> SurfaceData { auto Surface::loadSurface(const std::string& file_path) -> SurfaceData { // NOLINT(readability-convert-member-functions-to-static)
// Load file using ResourceHelper (supports both filesystem and pack) // Load file using ResourceHelper (supports both filesystem and pack)
std::vector<Uint8> buffer = Resource::Helper::loadFile(file_path); std::vector<Uint8> buffer = Resource::Helper::loadFile(file_path);
if (buffer.empty()) { if (buffer.empty()) {
@@ -148,14 +148,14 @@ void Surface::setColor(int index, Uint32 color) {
} }
// Rellena la superficie con un color // Rellena la superficie con un color
void Surface::clear(Uint8 color) { void Surface::clear(Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
const size_t TOTAL_PIXELS = surface_data_->width * surface_data_->height; const size_t TOTAL_PIXELS = surface_data_->width * surface_data_->height;
Uint8* data_ptr = surface_data_->data.get(); Uint8* data_ptr = surface_data_->data.get();
std::fill(data_ptr, data_ptr + TOTAL_PIXELS, color); std::fill(data_ptr, data_ptr + TOTAL_PIXELS, color);
} }
// Pone un pixel en la SurfaceData // Pone un pixel en la SurfaceData
void Surface::putPixel(int x, int y, Uint8 color) { void Surface::putPixel(int x, int y, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height) { if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height) {
return; // Coordenadas fuera de rango return; // Coordenadas fuera de rango
} }
@@ -168,7 +168,7 @@ void Surface::putPixel(int x, int y, Uint8 color) {
auto Surface::getPixel(int x, int y) -> Uint8 { return surface_data_->data.get()[x + (y * static_cast<int>(surface_data_->width))]; } auto Surface::getPixel(int x, int y) -> Uint8 { return surface_data_->data.get()[x + (y * static_cast<int>(surface_data_->width))]; }
// Dibuja un rectangulo relleno // Dibuja un rectangulo relleno
void Surface::fillRect(const SDL_FRect* rect, Uint8 color) { void Surface::fillRect(const SDL_FRect* rect, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
// Limitar los valores del rectángulo al tamaño de la superficie // Limitar los valores del rectángulo al tamaño de la superficie
float x_start = std::max(0.0F, rect->x); float x_start = std::max(0.0F, rect->x);
float y_start = std::max(0.0F, rect->y); float y_start = std::max(0.0F, rect->y);
@@ -185,7 +185,7 @@ void Surface::fillRect(const SDL_FRect* rect, Uint8 color) {
} }
// Dibuja el borde de un rectangulo // Dibuja el borde de un rectangulo
void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) { void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
// Limitar los valores del rectángulo al tamaño de la superficie // Limitar los valores del rectángulo al tamaño de la superficie
float x_start = std::max(0.0F, rect->x); float x_start = std::max(0.0F, rect->x);
float y_start = std::max(0.0F, rect->y); float y_start = std::max(0.0F, rect->y);
@@ -216,7 +216,7 @@ void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) {
} }
// Dibuja una linea // Dibuja una linea
void Surface::drawLine(float x1, float y1, float x2, float y2, Uint8 color) { void Surface::drawLine(float x1, float y1, float x2, float y2, Uint8 color) { // NOLINT(readability-convert-member-functions-to-static)
// Calcula las diferencias // Calcula las diferencias
float dx = std::abs(x2 - x1); float dx = std::abs(x2 - x1);
float dy = std::abs(y2 - y1); float dy = std::abs(y2 - y1);
@@ -250,7 +250,7 @@ void Surface::drawLine(float x1, float y1, float x2, float y2, Uint8 color) {
} }
} }
void Surface::render(float dx, float dy, float sx, float sy, float w, float h) { void Surface::render(float dx, float dy, float sx, float sy, float w, float h) { // NOLINT(readability-make-member-function-const)
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
// Limitar la región para evitar accesos fuera de rango en origen // Limitar la región para evitar accesos fuera de rango en origen
@@ -270,7 +270,7 @@ void Surface::render(float dx, float dy, float sx, float sy, float w, float h) {
int src_y = sy + iy; int src_y = sy + iy;
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))]; Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != transparent_color_) { if (color != static_cast<Uint8>(transparent_color_)) {
surface_data->data.get()[static_cast<size_t>(dest_x + (dest_y * surface_data->width))] = sub_palette_[color]; surface_data->data.get()[static_cast<size_t>(dest_x + (dest_y * surface_data->width))] = sub_palette_[color];
} }
} }
@@ -279,14 +279,14 @@ void Surface::render(float dx, float dy, float sx, float sy, float w, float h) {
} }
} }
void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { // NOLINT(readability-make-member-function-const)
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
// Determina la región de origen (clip) a renderizar // Determina la región de origen (clip) a renderizar
float sx = ((src_rect) != nullptr) ? src_rect->x : 0; float sx = (src_rect != nullptr) ? src_rect->x : 0;
float sy = ((src_rect) != nullptr) ? src_rect->y : 0; float sy = (src_rect != nullptr) ? src_rect->y : 0;
float w = ((src_rect) != nullptr) ? src_rect->w : surface_data_->width; float w = (src_rect != nullptr) ? src_rect->w : surface_data_->width;
float h = ((src_rect) != nullptr) ? src_rect->h : surface_data_->height; float h = (src_rect != nullptr) ? src_rect->h : surface_data_->height;
// Limitar la región para evitar accesos fuera de rango en origen // Limitar la región para evitar accesos fuera de rango en origen
w = std::min(w, surface_data_->width - sx); w = std::min(w, surface_data_->width - sx);
@@ -313,7 +313,7 @@ void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) {
if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) { if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) {
// Copia el píxel si no es transparente // Copia el píxel si no es transparente
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))]; Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != transparent_color_) { if (color != static_cast<Uint8>(transparent_color_)) {
surface_data_dest->data[dest_x + (dest_y * surface_data_dest->width)] = sub_palette_[color]; surface_data_dest->data[dest_x + (dest_y * surface_data_dest->width)] = sub_palette_[color];
} }
} }
@@ -334,7 +334,7 @@ void Surface::copyPixelIfNotTransparent(Uint8* dest_data, int dest_x, int dest_y
} }
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))]; Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != transparent_color_) { if (color != static_cast<Uint8>(transparent_color_)) {
dest_data[dest_x + (dest_y * dest_width)] = sub_palette_[color]; dest_data[dest_x + (dest_y * dest_width)] = sub_palette_[color];
} }
} }
@@ -344,16 +344,16 @@ void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
// Si srcRect es nullptr, tomar toda la superficie fuente // Si srcRect es nullptr, tomar toda la superficie fuente
float sx = ((src_rect) != nullptr) ? src_rect->x : 0; float sx = (src_rect != nullptr) ? src_rect->x : 0;
float sy = ((src_rect) != nullptr) ? src_rect->y : 0; float sy = (src_rect != nullptr) ? src_rect->y : 0;
float sw = ((src_rect) != nullptr) ? src_rect->w : surface_data_->width; float sw = (src_rect != nullptr) ? src_rect->w : surface_data_->width;
float sh = ((src_rect) != nullptr) ? src_rect->h : surface_data_->height; float sh = (src_rect != nullptr) ? src_rect->h : surface_data_->height;
// Si dstRect es nullptr, asignar las mismas dimensiones que srcRect // Si dstRect es nullptr, asignar las mismas dimensiones que srcRect
float dx = ((dst_rect) != nullptr) ? dst_rect->x : 0; float dx = (dst_rect != nullptr) ? dst_rect->x : 0;
float dy = ((dst_rect) != nullptr) ? dst_rect->y : 0; float dy = (dst_rect != nullptr) ? dst_rect->y : 0;
float dw = ((dst_rect) != nullptr) ? dst_rect->w : sw; float dw = (dst_rect != nullptr) ? dst_rect->w : sw;
float dh = ((dst_rect) != nullptr) ? dst_rect->h : sh; float dh = (dst_rect != nullptr) ? dst_rect->h : sh;
// Asegurarse de que srcRect y dstRect tienen las mismas dimensiones // Asegurarse de que srcRect y dstRect tienen las mismas dimensiones
if (sw != dw || sh != dh) { if (sw != dw || sh != dh) {
@@ -389,14 +389,14 @@ void Surface::render(SDL_FRect* src_rect, SDL_FRect* dst_rect, SDL_FlipMode flip
} }
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro // Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect, SDL_FlipMode flip) { void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect, SDL_FlipMode flip) const {
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData(); auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
// Determina la región de origen (clip) a renderizar // Determina la región de origen (clip) a renderizar
float sx = ((src_rect) != nullptr) ? src_rect->x : 0; float sx = (src_rect != nullptr) ? src_rect->x : 0;
float sy = ((src_rect) != nullptr) ? src_rect->y : 0; float sy = (src_rect != nullptr) ? src_rect->y : 0;
float w = ((src_rect) != nullptr) ? src_rect->w : surface_data_->width; float w = (src_rect != nullptr) ? src_rect->w : surface_data_->width;
float h = ((src_rect) != nullptr) ? src_rect->h : surface_data_->height; float h = (src_rect != nullptr) ? src_rect->h : surface_data_->height;
// Limitar la región para evitar accesos fuera de rango // Limitar la región para evitar accesos fuera de rango
w = std::min(w, surface_data_->width - sx); w = std::min(w, surface_data_->width - sx);
@@ -420,7 +420,7 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
// Copia el píxel si no es transparente // Copia el píxel si no es transparente
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))]; Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
if (color != transparent_color_) { if (color != static_cast<Uint8>(transparent_color_)) {
surface_data->data[dest_x + (dest_y * surface_data->width)] = surface_data->data[dest_x + (dest_y * surface_data->width)] =
(color == source_color) ? target_color : color; (color == source_color) ? target_color : color;
} }
@@ -449,7 +449,7 @@ static auto computeFadeDensity(int screen_y, int fade_h, int canvas_height) -> f
} }
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig) // 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) { void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect) const {
const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0; 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 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 SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
@@ -472,7 +472,7 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
} }
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_) { if (COLOR == static_cast<Uint8>(transparent_color_)) {
continue; continue;
} }
@@ -486,7 +486,7 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
} }
// Idem però reemplaçant un color índex // 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) { void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect) const {
const int SX = (src_rect != nullptr) ? static_cast<int>(src_rect->x) : 0; 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 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 SW = (src_rect != nullptr) ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
@@ -509,7 +509,7 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
} }
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_) { if (COLOR == static_cast<Uint8>(transparent_color_)) {
continue; continue;
} }
@@ -525,19 +525,29 @@ void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height
// Vuelca los píxeles como ARGB8888 a un buffer externo (sin SDL_Texture ni SDL_Renderer) // Vuelca los píxeles como ARGB8888 a un buffer externo (sin SDL_Texture ni SDL_Renderer)
void Surface::toARGBBuffer(Uint32* buffer) const { void Surface::toARGBBuffer(Uint32* buffer) const {
if (!surface_data_ || (surface_data_->data == nullptr)) { return; } if (!surface_data_ || !surface_data_->data || !buffer) { return; }
const int WIDTH = static_cast<int>(surface_data_->width); const int WIDTH = static_cast<int>(surface_data_->width);
const int HEIGHT = static_cast<int>(surface_data_->height); const int HEIGHT = static_cast<int>(surface_data_->height);
const Uint8* src = surface_data_->data.get(); const Uint8* src = surface_data_->data.get();
for (int y = 0; y < HEIGHT; ++y) {
for (int x = 0; x < WIDTH; ++x) { // Obtenemos el tamaño de la paleta para evitar accesos fuera de rango
buffer[(y * WIDTH) + x] = palette_[src[(y * WIDTH) + x]]; const size_t PAL_SIZE = palette_.size();
for (int i = 0; i < WIDTH * HEIGHT; ++i) {
Uint8 color_index = src[i];
// Verificación de seguridad: ¿El índice existe en la paleta?
if (color_index < PAL_SIZE) {
buffer[i] = palette_[color_index];
} else {
buffer[i] = 0xFF000000; // Negro opaco si el índice es erróneo
} }
} }
} }
// Vuelca la superficie a una textura // Vuelca la superficie a una textura
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) { void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) { // NOLINT(readability-convert-member-functions-to-static)
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) { if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {
throw std::runtime_error("Renderer or texture is null."); throw std::runtime_error("Renderer or texture is null.");
} }
@@ -576,7 +586,7 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) {
} }
// Vuelca la superficie a una textura // Vuelca la superficie a una textura
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect) { void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FRect* src_rect, SDL_FRect* dest_rect) { // NOLINT(readability-convert-member-functions-to-static)
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) { if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {
throw std::runtime_error("Renderer or texture is null."); throw std::runtime_error("Renderer or texture is null.");
} }
@@ -621,7 +631,7 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FR
} }
// Realiza un efecto de fundido en la paleta principal // Realiza un efecto de fundido en la paleta principal
auto Surface::fadePalette() -> bool { auto Surface::fadePalette() -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Verificar que el tamaño mínimo de palette_ sea adecuado // Verificar que el tamaño mínimo de palette_ sea adecuado
static constexpr int PALETTE_SIZE = 19; static constexpr int PALETTE_SIZE = 19;
if (sizeof(palette_) / sizeof(palette_[0]) < PALETTE_SIZE) { if (sizeof(palette_) / sizeof(palette_[0]) < PALETTE_SIZE) {
@@ -641,7 +651,7 @@ auto Surface::fadePalette() -> bool {
} }
// Realiza un efecto de fundido en la paleta secundaria // Realiza un efecto de fundido en la paleta secundaria
auto Surface::fadeSubPalette(Uint32 delay) -> bool { auto Surface::fadeSubPalette(Uint32 delay) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Variable estática para almacenar el último tick // Variable estática para almacenar el último tick
static Uint32 last_tick_ = 0; static Uint32 last_tick_ = 0;
@@ -675,4 +685,4 @@ auto Surface::fadeSubPalette(Uint32 delay) -> bool {
} }
// Restaura la sub paleta a su estado original // Restaura la sub paleta a su estado original
void Surface::resetSubPalette() { initializeSubPalette(sub_palette_); } void Surface::resetSubPalette() { initializeSubPalette(sub_palette_); } // NOLINT(readability-convert-member-functions-to-static)

View File

@@ -82,13 +82,13 @@ class Surface {
void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); void render(SDL_FRect* src_rect = nullptr, SDL_FRect* dst_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro // Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE) const;
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig) // Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect = nullptr); void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect = nullptr) const;
// Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color) // Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color)
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect = nullptr); void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color, SDL_FRect* src_rect = nullptr) const;
// Establece un color en la paleta // Establece un color en la paleta
void setColor(int index, Uint32 color); void setColor(int index, Uint32 color);

View File

@@ -8,23 +8,37 @@
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/sprite/sprite.hpp" // Para SSprite
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/surface_sprite.hpp" // Para SSprite
#include "core/resources/resource_helper.hpp" // Para ResourceHelper #include "core/resources/resource_helper.hpp" // Para ResourceHelper
#include "utils/utils.hpp" // Para getFileName, stringToColor, printWithDots #include "utils/utils.hpp" // Para getFileName, stringToColor, printWithDots
// Extrae el siguiente codepoint UTF-8 de la cadena, avanzando 'pos' al byte siguiente // Extrae el siguiente codepoint UTF-8 de la cadena, avanzando 'pos' al byte siguiente
auto Text::nextCodepoint(const std::string& s, size_t& pos) -> uint32_t { auto Text::nextCodepoint(const std::string& s, size_t& pos) -> uint32_t { // NOLINT(readability-convert-member-functions-to-static)
auto c = static_cast<unsigned char>(s[pos]); auto c = static_cast<unsigned char>(s[pos]);
uint32_t cp = 0; uint32_t cp = 0;
size_t extra = 0; size_t extra = 0;
if (c < 0x80) { cp = c; extra = 0; } if (c < 0x80) {
else if (c < 0xC0) { pos++; return 0xFFFD; } // byte de continuación suelto cp = c;
else if (c < 0xE0) { cp = c & 0x1F; extra = 1; } extra = 0;
else if (c < 0xF0) { cp = c & 0x0F; extra = 2; } } else if (c < 0xC0) {
else if (c < 0xF8) { cp = c & 0x07; extra = 3; } pos++;
else { pos++; return 0xFFFD; } return 0xFFFD;
} // byte de continuación suelto
else if (c < 0xE0) {
cp = c & 0x1F;
extra = 1;
} else if (c < 0xF0) {
cp = c & 0x0F;
extra = 2;
} else if (c < 0xF8) {
cp = c & 0x07;
extra = 3;
} else {
pos++;
return 0xFFFD;
}
pos++; pos++;
for (size_t i = 0; i < extra && pos < s.size(); ++i, ++pos) { for (size_t i = 0; i < extra && pos < s.size(); ++i, ++pos) {
@@ -36,7 +50,7 @@ auto Text::nextCodepoint(const std::string& s, size_t& pos) -> uint32_t {
} }
// Convierte un codepoint Unicode a una cadena UTF-8 // Convierte un codepoint Unicode a una cadena UTF-8
auto Text::codepointToUtf8(uint32_t cp) -> std::string { auto Text::codepointToUtf8(uint32_t cp) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
std::string result; std::string result;
if (cp < 0x80) { if (cp < 0x80) {
result += static_cast<char>(cp); result += static_cast<char>(cp);
@@ -58,7 +72,7 @@ auto Text::codepointToUtf8(uint32_t cp) -> std::string {
// Carga un fichero de definición de fuente .fnt // Carga un fichero de definición de fuente .fnt
// Formato: líneas "clave valor", comentarios con #, gliphos como "codepoint ancho" // Formato: líneas "clave valor", comentarios con #, gliphos como "codepoint ancho"
auto Text::loadTextFile(const std::string& file_path) -> std::shared_ptr<File> { auto Text::loadTextFile(const std::string& file_path) -> std::shared_ptr<File> { // NOLINT(readability-convert-member-functions-to-static)
auto tf = std::make_shared<File>(); auto tf = std::make_shared<File>();
auto file_data = Resource::Helper::loadFile(file_path); auto file_data = Resource::Helper::loadFile(file_path);
@@ -101,9 +115,9 @@ auto Text::loadTextFile(const std::string& file_path) -> std::shared_ptr<File> {
continue; // línea mal formateada, ignorar continue; // línea mal formateada, ignorar
} }
Offset off{}; Offset off{};
const int row_sp = tf->row_spacing > 0 ? tf->row_spacing : tf->cell_spacing; const int ROW_SP = tf->row_spacing > 0 ? tf->row_spacing : tf->cell_spacing;
off.x = (glyph_index % tf->columns) * (tf->box_width + tf->cell_spacing) + tf->cell_spacing; off.x = ((glyph_index % tf->columns) * (tf->box_width + tf->cell_spacing)) + tf->cell_spacing;
off.y = (glyph_index / tf->columns) * (tf->box_height + row_sp) + tf->cell_spacing; off.y = ((glyph_index / tf->columns) * (tf->box_height + ROW_SP)) + tf->cell_spacing;
off.w = width; off.w = width;
tf->offset[codepoint] = off; tf->offset[codepoint] = off;
++glyph_index; ++glyph_index;
@@ -122,19 +136,19 @@ Text::Text(const std::shared_ptr<Surface>& surface, const std::string& text_file
box_width_ = tf->box_width; box_width_ = tf->box_width;
offset_ = tf->offset; offset_ = tf->offset;
sprite_ = std::make_unique<SurfaceSprite>(surface, (SDL_FRect){0.0F, 0.0F, static_cast<float>(box_width_), static_cast<float>(box_height_)}); sprite_ = std::make_unique<Sprite>(surface, SDL_FRect{.x = 0.0F, .y = 0.0F, .w = static_cast<float>(box_width_), .h = static_cast<float>(box_height_)});
} }
// Constructor desde estructura precargada // Constructor desde estructura precargada
Text::Text(const std::shared_ptr<Surface>& surface, const std::shared_ptr<File>& text_file) Text::Text(const std::shared_ptr<Surface>& surface, const std::shared_ptr<File>& text_file)
: sprite_(std::make_unique<SurfaceSprite>(surface, (SDL_FRect){0.0F, 0.0F, static_cast<float>(text_file->box_width), static_cast<float>(text_file->box_height)})), : sprite_(std::make_unique<Sprite>(surface, SDL_FRect{.x = 0.0F, .y = 0.0F, .w = static_cast<float>(text_file->box_width), .h = static_cast<float>(text_file->box_height)})),
box_width_(text_file->box_width), box_width_(text_file->box_width),
box_height_(text_file->box_height), box_height_(text_file->box_height),
offset_(text_file->offset) { offset_(text_file->offset) {
} }
// Escribe texto en pantalla // Escribe texto en pantalla
void Text::write(int x, int y, const std::string& text, int kerning, int lenght) { void Text::write(int x, int y, const std::string& text, int kerning, int lenght) { // NOLINT(readability-convert-member-functions-to-static)
int shift = 0; int shift = 0;
int glyphs_done = 0; int glyphs_done = 0;
size_t pos = 0; size_t pos = 0;
@@ -156,7 +170,7 @@ void Text::write(int x, int y, const std::string& text, int kerning, int lenght)
} }
// Escribe el texto en una surface // Escribe el texto en una surface
auto Text::writeToSurface(const std::string& text, int zoom, int kerning) -> std::shared_ptr<Surface> { auto Text::writeToSurface(const std::string& text, int zoom, int kerning) -> std::shared_ptr<Surface> { // NOLINT(readability-make-member-function-const)
auto width = length(text, kerning) * zoom; auto width = length(text, kerning) * zoom;
auto height = box_height_ * zoom; auto height = box_height_ * zoom;
auto surface = std::make_shared<Surface>(width, height); auto surface = std::make_shared<Surface>(width, height);
@@ -170,7 +184,7 @@ auto Text::writeToSurface(const std::string& text, int zoom, int kerning) -> std
} }
// Escribe el texto con extras en una surface // Escribe el texto con extras en una surface
auto Text::writeDXToSurface(Uint8 flags, const std::string& text, int kerning, Uint8 text_color, Uint8 shadow_distance, Uint8 shadow_color, int lenght) -> std::shared_ptr<Surface> { auto Text::writeDXToSurface(Uint8 flags, const std::string& text, int kerning, Uint8 text_color, Uint8 shadow_distance, Uint8 shadow_color, int lenght) -> std::shared_ptr<Surface> { // NOLINT(readability-make-member-function-const)
auto width = Text::length(text, kerning) + shadow_distance; auto width = Text::length(text, kerning) + shadow_distance;
auto height = box_height_ + shadow_distance; auto height = box_height_ + shadow_distance;
auto surface = std::make_shared<Surface>(width, height); auto surface = std::make_shared<Surface>(width, height);
@@ -184,7 +198,7 @@ auto Text::writeDXToSurface(Uint8 flags, const std::string& text, int kerning, U
} }
// Escribe el texto con colores // Escribe el texto con colores
void Text::writeColored(int x, int y, const std::string& text, Uint8 color, int kerning, int lenght) { void Text::writeColored(int x, int y, const std::string& text, Uint8 color, int kerning, int lenght) { // NOLINT(readability-convert-member-functions-to-static)
int shift = 0; int shift = 0;
int glyphs_done = 0; int glyphs_done = 0;
size_t pos = 0; size_t pos = 0;
@@ -218,11 +232,11 @@ void Text::writeCentered(int x, int y, const std::string& text, int kerning, int
} }
// Escribe texto con extras // Escribe texto con extras
void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning, Uint8 text_color, Uint8 shadow_distance, Uint8 shadow_color, int lenght) { void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning, Uint8 text_color, Uint8 shadow_distance, Uint8 shadow_color, int lenght) { // NOLINT(readability-convert-member-functions-to-static)
const auto CENTERED = ((flags & CENTER_FLAG) == CENTER_FLAG); const auto CENTERED = ((flags & CENTER_FLAG) == CENTER_FLAG);
const auto SHADOWED = ((flags & SHADOW_FLAG) == SHADOW_FLAG); const auto SHADOWED = ((flags & SHADOW_FLAG) == SHADOW_FLAG);
const auto COLORED = ((flags & COLOR_FLAG) == COLOR_FLAG); const auto COLORED = ((flags & COLOR_FLAG) == COLOR_FLAG);
const auto STROKED = ((flags & STROKE_FLAG) == STROKE_FLAG); const auto STROKED = ((flags & STROKE_FLAG) == STROKE_FLAG);
if (CENTERED) { if (CENTERED) {
x -= (Text::length(text, kerning) / 2); x -= (Text::length(text, kerning) / 2);
@@ -233,7 +247,8 @@ void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerni
} }
if (STROKED) { if (STROKED) {
for (int dist = 1; dist <= shadow_distance; ++dist) { const int MAX_DIST = static_cast<int>(shadow_distance);
for (int dist = 1; dist <= MAX_DIST; ++dist) {
for (int dy = -dist; dy <= dist; ++dy) { for (int dy = -dist; dy <= dist; ++dy) {
for (int dx = -dist; dx <= dist; ++dx) { for (int dx = -dist; dx <= dist; ++dx) {
writeColored(x + dx, y + dy, text, shadow_color, kerning, lenght); writeColored(x + dx, y + dy, text, shadow_color, kerning, lenght);
@@ -250,7 +265,7 @@ void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerni
} }
// Obtiene la longitud en pixels de una cadena UTF-8 // Obtiene la longitud en pixels de una cadena UTF-8
auto Text::length(const std::string& text, int kerning) const -> int { auto Text::length(const std::string& text, int kerning) const -> int { // NOLINT(readability-convert-member-functions-to-static)
int shift = 0; int shift = 0;
size_t pos = 0; size_t pos = 0;
@@ -267,7 +282,7 @@ auto Text::length(const std::string& text, int kerning) const -> int {
} }
// Devuelve el ancho en pixels de un glifo dado su codepoint Unicode // Devuelve el ancho en pixels de un glifo dado su codepoint Unicode
auto Text::glyphWidth(uint32_t codepoint, int kerning) const -> int { auto Text::glyphWidth(uint32_t codepoint, int kerning) const -> int { // NOLINT(readability-convert-member-functions-to-static)
auto it = offset_.find(codepoint); auto it = offset_.find(codepoint);
if (it == offset_.end()) { it = offset_.find('?'); } if (it == offset_.end()) { it = offset_.find('?'); }
if (it != offset_.end()) { return it->second.w + kerning; } if (it != offset_.end()) { return it->second.w + kerning; }
@@ -280,9 +295,9 @@ auto Text::getGlyphClip(uint32_t codepoint) const -> SDL_FRect {
if (it == offset_.end()) { it = offset_.find('?'); } if (it == offset_.end()) { it = offset_.find('?'); }
if (it == offset_.end()) { return {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; } if (it == offset_.end()) { return {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; }
return {.x = static_cast<float>(it->second.x), return {.x = static_cast<float>(it->second.x),
.y = static_cast<float>(it->second.y), .y = static_cast<float>(it->second.y),
.w = static_cast<float>(box_width_), .w = static_cast<float>(box_width_),
.h = static_cast<float>(box_height_)}; .h = static_cast<float>(box_height_)};
} }
// Devuelve el tamaño de la caja de cada caracter // Devuelve el tamaño de la caja de cada caracter

View File

@@ -2,12 +2,12 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <memory> // Para shared_ptr, unique_ptr #include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string #include <string> // Para string
#include <unordered_map> // Para unordered_map #include <unordered_map> // Para unordered_map
#include "core/rendering/surface_sprite.hpp" // Para SSprite #include "core/rendering/sprite/sprite.hpp" // Para SSprite
class Surface; // Forward declaration class Surface; // Forward declaration
// Clase texto. Pinta texto en pantalla a partir de un bitmap con soporte UTF-8 // Clase texto. Pinta texto en pantalla a partir de un bitmap con soporte UTF-8
class Text { class Text {
@@ -18,11 +18,11 @@ class Text {
}; };
struct File { struct File {
int box_width{0}; // Anchura de la caja de cada caracter en el png int box_width{0}; // Anchura de la caja de cada caracter en el png
int box_height{0}; // Altura de la caja de cada caracter en el png int box_height{0}; // Altura de la caja de cada caracter en el png
int columns{16}; // Número de columnas en el bitmap int columns{16}; // Número de columnas en el bitmap
int cell_spacing{0}; // Píxeles de separación entre columnas (y borde izquierdo/superior) int cell_spacing{0}; // Píxeles de separación entre columnas (y borde izquierdo/superior)
int row_spacing{0}; // Píxeles de separación entre filas (si difiere de cell_spacing) int row_spacing{0}; // Píxeles de separación entre filas (si difiere de cell_spacing)
std::unordered_map<uint32_t, Offset> offset; // Posición y ancho de cada glifo (clave: codepoint Unicode) std::unordered_map<uint32_t, Offset> offset; // Posición y ancho de cada glifo (clave: codepoint Unicode)
}; };
@@ -48,11 +48,11 @@ class Text {
auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura
auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura
[[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena [[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena
[[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter [[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter
[[nodiscard]] auto glyphWidth(uint32_t codepoint, int kerning = 0) const -> int; // Devuelve el ancho en pixels de un glifo [[nodiscard]] auto glyphWidth(uint32_t codepoint, int kerning = 0) const -> int; // Devuelve el ancho en pixels de un glifo
[[nodiscard]] auto getGlyphClip(uint32_t codepoint) const -> SDL_FRect; // Devuelve el clip rect del glifo [[nodiscard]] auto getGlyphClip(uint32_t codepoint) const -> SDL_FRect; // Devuelve el clip rect del glifo
[[nodiscard]] auto getSprite() const -> SurfaceSprite* { return sprite_.get(); } // Acceso al sprite interno [[nodiscard]] auto getSprite() const -> Sprite* { return sprite_.get(); } // Acceso al sprite interno
void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra
@@ -62,11 +62,11 @@ class Text {
private: private:
// Objetos y punteros // Objetos y punteros
std::unique_ptr<SurfaceSprite> sprite_ = nullptr; // Objeto con los graficos para el texto std::unique_ptr<Sprite> sprite_ = nullptr; // Objeto con los graficos para el texto
// Variables // Variables
int box_width_ = 0; // Anchura de la caja de cada caracter en el png int box_width_ = 0; // Anchura de la caja de cada caracter en el png
int box_height_ = 0; // Altura de la caja de cada caracter en el png int box_height_ = 0; // Altura de la caja de cada caracter en el png
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija
std::unordered_map<uint32_t, Offset> offset_; // Posición y ancho de cada glifo (clave: codepoint Unicode) std::unordered_map<uint32_t, Offset> offset_; // Posición y ancho de cada glifo (clave: codepoint Unicode)
}; };

View File

@@ -1,163 +0,0 @@
#include "core/rendering/texture.hpp"
#include <SDL3/SDL.h>
#include <iostream> // Para basic_ostream, operator<<, endl, cout
#include <stdexcept> // Para runtime_error
#include <string> // Para char_traits, operator<<, string, opera...
#include <utility>
#include <vector> // Para vector
#include "utils/utils.hpp" // Para getFileName, Color, printWithDots
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h" // para stbi_failure_reason, stbi_image_free
// Constructor
Texture::Texture(SDL_Renderer* renderer, std::string path)
: renderer_(renderer),
path_(std::move(path)) {
// Carga el fichero en la textura
if (!path_.empty()) {
// Obtiene la extensión
const std::string EXTENSION = path_.substr(path_.find_last_of('.') + 1);
// .png
if (EXTENSION == "png") {
loadFromFile(path_);
}
}
}
// Destructor
Texture::~Texture() {
unloadTexture();
palettes_.clear();
}
// Carga una imagen desde un fichero
auto Texture::loadFromFile(const std::string& file_path) -> bool {
if (file_path.empty()) {
return false;
}
int req_format = STBI_rgb_alpha;
int width;
int height;
int orig_format;
unsigned char* data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format);
if (data == nullptr) {
std::cerr << "Error: Fichero no encontrado " << getFileName(file_path) << '\n';
throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path));
}
printWithDots("Image : ", getFileName(file_path), "[ LOADED ]");
int pitch;
SDL_PixelFormat pixel_format;
// STBI_rgb_alpha (RGBA)
pitch = 4 * width;
pixel_format = SDL_PIXELFORMAT_RGBA32;
// Limpia
unloadTexture();
// La textura final
SDL_Texture* new_texture = nullptr;
// Carga la imagen desde una ruta específica
auto* loaded_surface = SDL_CreateSurfaceFrom(width, height, pixel_format, static_cast<void*>(data), pitch);
if (loaded_surface == nullptr) {
std::cout << "Unable to load image " << file_path << '\n';
} else {
// Crea la textura desde los pixels de la surface
new_texture = SDL_CreateTextureFromSurface(renderer_, loaded_surface);
if (new_texture == nullptr) {
std::cout << "Unable to create texture from " << file_path << "! SDL Error: " << SDL_GetError() << '\n';
} else {
// Obtiene las dimensiones de la imagen
width_ = loaded_surface->w;
height_ = loaded_surface->h;
}
// Elimina la textura cargada
SDL_DestroySurface(loaded_surface);
}
// Return success
stbi_image_free(data);
texture_ = new_texture;
return texture_ != nullptr;
}
// Crea una textura en blanco
auto Texture::createBlank(int width, int height, SDL_PixelFormat format, SDL_TextureAccess access) -> bool {
// Crea una textura sin inicializar
texture_ = SDL_CreateTexture(renderer_, format, access, width, height);
if (texture_ == nullptr) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create blank texture! SDL Error: %s", SDL_GetError());
} else {
width_ = width;
height_ = height;
}
return texture_ != nullptr;
}
// Libera la memoria de la textura
void Texture::unloadTexture() {
// Libera la textura
if (texture_ != nullptr) {
SDL_DestroyTexture(texture_);
texture_ = nullptr;
width_ = 0;
height_ = 0;
}
}
// Establece el color para la modulacion
void Texture::setColor(Uint8 red, Uint8 green, Uint8 blue) { SDL_SetTextureColorMod(texture_, red, green, blue); }
void Texture::setColor(Color color) { SDL_SetTextureColorMod(texture_, color.r, color.g, color.b); }
// Establece el blending
void Texture::setBlendMode(SDL_BlendMode blending) { SDL_SetTextureBlendMode(texture_, blending); }
// Establece el alpha para la modulación
void Texture::setAlpha(Uint8 alpha) { SDL_SetTextureAlphaMod(texture_, alpha); }
// Renderiza la textura en un punto específico
void Texture::render(float x, float y, SDL_FRect* clip, float zoom_w, float zoom_h, double angle, SDL_FPoint* center, SDL_FlipMode flip) {
// Establece el destino de renderizado en la pantalla
SDL_FRect render_quad = {x, y, width_, height_};
// Obtiene las dimesiones del clip de renderizado
if (clip != nullptr) {
render_quad.w = clip->w;
render_quad.h = clip->h;
}
// Calcula el zoom y las coordenadas
if (zoom_h != 1.0F || zoom_w != 1.0F) {
render_quad.x = render_quad.x + (render_quad.w / 2);
render_quad.y = render_quad.y + (render_quad.h / 2);
render_quad.w = render_quad.w * zoom_w;
render_quad.h = render_quad.h * zoom_h;
render_quad.x = render_quad.x - (render_quad.w / 2);
render_quad.y = render_quad.y - (render_quad.h / 2);
}
// Renderiza a pantalla
SDL_RenderTextureRotated(renderer_, texture_, clip, &render_quad, angle, center, flip);
}
// Establece la textura como objetivo de renderizado
void Texture::setAsRenderTarget(SDL_Renderer* renderer) { SDL_SetRenderTarget(renderer, texture_); }
// Recarga la textura
auto Texture::reLoad() -> bool { return loadFromFile(path_); }
// Obtiene la textura
auto Texture::getSDLTexture() -> SDL_Texture* { return texture_; }
// Obtiene el renderizador
auto Texture::getRenderer() -> SDL_Renderer* { return renderer_; }

View File

@@ -1,43 +0,0 @@
#pragma once
#include <SDL3/SDL.h>
#include <string> // Para string
#include <vector> // Para vector
struct Color; // lines 11-11
class Texture {
public:
explicit Texture(SDL_Renderer* renderer, std::string path = std::string()); // Constructor
~Texture(); // Destructor
auto loadFromFile(const std::string& path) -> bool; // Carga una imagen desde un fichero
auto createBlank(int width, int height, SDL_PixelFormat format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess access = SDL_TEXTUREACCESS_STREAMING) -> bool; // Crea una textura en blanco
auto reLoad() -> bool; // Recarga la textura
void setColor(Uint8 red, Uint8 green, Uint8 blue); // Establece el color para la modulacion
void setColor(Color color); // Establece el color para la modulacion
void setBlendMode(SDL_BlendMode blending); // Establece el blending
void setAlpha(Uint8 alpha); // Establece el alpha para la modulación
void setAsRenderTarget(SDL_Renderer* renderer); // Establece la textura como objetivo de renderizado
void render(float x, float y, SDL_FRect* clip = nullptr, float zoom_w = 1, float zoom_h = 1, double angle = 0.0, SDL_FPoint* center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Renderiza la textura en un punto específico
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene el ancho de la imagen
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene el alto de la imagen
auto getSDLTexture() -> SDL_Texture*; // Obtiene la textura
auto getRenderer() -> SDL_Renderer*; // Obtiene el renderizador
private:
void unloadTexture(); // Libera la memoria de la textura
// Objetos y punteros
SDL_Renderer* renderer_; // Renderizador donde dibujar la textura
SDL_Texture* texture_ = nullptr; // La textura
// Variables
std::string path_; // Ruta de la imagen de la textura
float width_ = 0.0F; // Ancho de la imagen
float height_ = 0.0F; // Alto de la imagen
std::vector<std::vector<Uint32>> palettes_; // Vector con las diferentes paletas
};

View File

@@ -76,8 +76,8 @@ namespace Resource {
} }
// Obtiene el sonido a partir de un nombre // Obtiene el sonido a partir de un nombre
auto Cache::getSound(const std::string& name) -> JA_Sound_t* { auto Cache::getSound(const std::string& name) -> JA_Sound_t* { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) { return s.name == name; }); auto it = std::ranges::find_if(sounds_, [&name](const auto& s) -> bool { return s.name == name; });
if (it != sounds_.end()) { if (it != sounds_.end()) {
return it->sound; return it->sound;
@@ -88,8 +88,8 @@ namespace Resource {
} }
// Obtiene la música a partir de un nombre // Obtiene la música a partir de un nombre
auto Cache::getMusic(const std::string& name) -> JA_Music_t* { auto Cache::getMusic(const std::string& name) -> JA_Music_t* { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(musics_, [&name](const auto& m) { return m.name == name; }); auto it = std::ranges::find_if(musics_, [&name](const auto& m) -> bool { return m.name == name; });
if (it != musics_.end()) { if (it != musics_.end()) {
return it->music; return it->music;
@@ -100,8 +100,8 @@ namespace Resource {
} }
// Obtiene la surface a partir de un nombre // Obtiene la surface a partir de un nombre
auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> { auto Cache::getSurface(const std::string& name) -> std::shared_ptr<Surface> { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) { return t.name == name; }); auto it = std::ranges::find_if(surfaces_, [&name](const auto& t) -> bool { return t.name == name; });
if (it != surfaces_.end()) { if (it != surfaces_.end()) {
return it->surface; return it->surface;
@@ -112,8 +112,8 @@ namespace Resource {
} }
// Obtiene la paleta a partir de un nombre // Obtiene la paleta a partir de un nombre
auto Cache::getPalette(const std::string& name) -> Palette { auto Cache::getPalette(const std::string& name) -> Palette { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(palettes_, [&name](const auto& t) { return t.name == name; }); auto it = std::ranges::find_if(palettes_, [&name](const auto& t) -> bool { return t.name == name; });
if (it != palettes_.end()) { if (it != palettes_.end()) {
return it->palette; return it->palette;
@@ -124,8 +124,8 @@ namespace Resource {
} }
// Obtiene el fichero de texto a partir de un nombre // Obtiene el fichero de texto a partir de un nombre
auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<Text::File> { auto Cache::getTextFile(const std::string& name) -> std::shared_ptr<Text::File> { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(text_files_, [&name](const auto& t) { return t.name == name; }); auto it = std::ranges::find_if(text_files_, [&name](const auto& t) -> bool { return t.name == name; });
if (it != text_files_.end()) { if (it != text_files_.end()) {
return it->text_file; return it->text_file;
@@ -136,8 +136,8 @@ namespace Resource {
} }
// Obtiene el objeto de texto a partir de un nombre // Obtiene el objeto de texto a partir de un nombre
auto Cache::getText(const std::string& name) -> std::shared_ptr<Text> { auto Cache::getText(const std::string& name) -> std::shared_ptr<Text> { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(texts_, [&name](const auto& t) { return t.name == name; }); auto it = std::ranges::find_if(texts_, [&name](const auto& t) -> bool { return t.name == name; });
if (it != texts_.end()) { if (it != texts_.end()) {
return it->text; return it->text;
@@ -148,8 +148,8 @@ namespace Resource {
} }
// Obtiene los datos de animación parseados a partir de un nombre // Obtiene los datos de animación parseados a partir de un nombre
auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& { auto Cache::getAnimationData(const std::string& name) -> const AnimationResource& { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(animations_, [&name](const auto& a) { return a.name == name; }); auto it = std::ranges::find_if(animations_, [&name](const auto& a) -> bool { return a.name == name; });
if (it != animations_.end()) { if (it != animations_.end()) {
return *it; return *it;
@@ -160,8 +160,8 @@ namespace Resource {
} }
// Obtiene la habitación a partir de un nombre // Obtiene la habitación a partir de un nombre
auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> { auto Cache::getRoom(const std::string& name) -> std::shared_ptr<Room::Data> { // NOLINT(readability-convert-member-functions-to-static)
auto it = std::ranges::find_if(rooms_, [&name](const auto& r) { return r.name == name; }); auto it = std::ranges::find_if(rooms_, [&name](const auto& r) -> bool { return r.name == name; });
if (it != rooms_.end()) { if (it != rooms_.end()) {
return it->room; return it->room;
@@ -177,7 +177,7 @@ namespace Resource {
} }
// Helper para lanzar errores de carga con formato consistente // 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) { [[noreturn]] void Cache::throwLoadError(const std::string& asset_type, const std::string& file_path, const std::exception& e) { // NOLINT(readability-convert-member-functions-to-static)
std::cerr << "\n[ ERROR ] Failed to load " << asset_type << ": " << getFileName(file_path) << '\n'; std::cerr << "\n[ ERROR ] Failed to load " << asset_type << ": " << getFileName(file_path) << '\n';
std::cerr << "[ ERROR ] Path: " << file_path << '\n'; std::cerr << "[ ERROR ] Path: " << file_path << '\n';
std::cerr << "[ ERROR ] Reason: " << e.what() << '\n'; std::cerr << "[ ERROR ] Reason: " << e.what() << '\n';
@@ -186,7 +186,7 @@ namespace Resource {
} }
// Carga los sonidos // Carga los sonidos
void Cache::loadSounds() { void Cache::loadSounds() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> SOUND FILES" << '\n'; std::cout << "\n>> SOUND FILES" << '\n';
auto list = List::get()->getListByType(List::Type::SOUND); auto list = List::get()->getListByType(List::Type::SOUND);
sounds_.clear(); sounds_.clear();
@@ -221,7 +221,7 @@ namespace Resource {
} }
// Carga las musicas // Carga las musicas
void Cache::loadMusics() { void Cache::loadMusics() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> MUSIC FILES" << '\n'; std::cout << "\n>> MUSIC FILES" << '\n';
auto list = List::get()->getListByType(List::Type::MUSIC); auto list = List::get()->getListByType(List::Type::MUSIC);
musics_.clear(); musics_.clear();
@@ -256,7 +256,7 @@ namespace Resource {
} }
// Carga las texturas // Carga las texturas
void Cache::loadSurfaces() { void Cache::loadSurfaces() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> SURFACES" << '\n'; std::cout << "\n>> SURFACES" << '\n';
auto list = List::get()->getListByType(List::Type::BITMAP); auto list = List::get()->getListByType(List::Type::BITMAP);
surfaces_.clear(); surfaces_.clear();
@@ -283,7 +283,7 @@ namespace Resource {
} }
// Carga las paletas // Carga las paletas
void Cache::loadPalettes() { void Cache::loadPalettes() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> PALETTES" << '\n'; std::cout << "\n>> PALETTES" << '\n';
auto list = List::get()->getListByType(List::Type::PALETTE); auto list = List::get()->getListByType(List::Type::PALETTE);
palettes_.clear(); palettes_.clear();
@@ -300,7 +300,7 @@ namespace Resource {
} }
// Carga los ficheros de texto // Carga los ficheros de texto
void Cache::loadTextFiles() { void Cache::loadTextFiles() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> TEXT FILES" << '\n'; std::cout << "\n>> TEXT FILES" << '\n';
auto list = List::get()->getListByType(List::Type::FONT); auto list = List::get()->getListByType(List::Type::FONT);
text_files_.clear(); text_files_.clear();
@@ -317,7 +317,7 @@ namespace Resource {
} }
// Carga las animaciones // Carga las animaciones
void Cache::loadAnimations() { void Cache::loadAnimations() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> ANIMATIONS" << '\n'; std::cout << "\n>> ANIMATIONS" << '\n';
auto list = List::get()->getListByType(List::Type::ANIMATION); auto list = List::get()->getListByType(List::Type::ANIMATION);
animations_.clear(); animations_.clear();
@@ -343,7 +343,7 @@ namespace Resource {
} }
// Carga las habitaciones desde archivos YAML // Carga las habitaciones desde archivos YAML
void Cache::loadRooms() { void Cache::loadRooms() { // NOLINT(readability-convert-member-functions-to-static)
std::cout << "\n>> ROOMS" << '\n'; std::cout << "\n>> ROOMS" << '\n';
auto list = List::get()->getListByType(List::Type::ROOM); auto list = List::get()->getListByType(List::Type::ROOM);
rooms_.clear(); rooms_.clear();
@@ -360,7 +360,7 @@ namespace Resource {
} }
} }
void Cache::createText() { void Cache::createText() { // NOLINT(readability-convert-member-functions-to-static)
struct ResourceInfo { struct ResourceInfo {
std::string key; // Identificador del recurso std::string key; // Identificador del recurso
std::string texture_file; // Nombre del archivo de textura std::string texture_file; // Nombre del archivo de textura
@@ -461,12 +461,12 @@ namespace Resource {
// Draw progress bar border // Draw progress bar border
const float WIRED_BAR_WIDTH = Options::game.width - (X_PADDING * 2); const float WIRED_BAR_WIDTH = Options::game.width - (X_PADDING * 2);
SDL_FRect rect_wired = {X_PADDING, BAR_POSITION, WIRED_BAR_WIDTH, BAR_HEIGHT}; SDL_FRect rect_wired = {.x = X_PADDING, .y = BAR_POSITION, .w = WIRED_BAR_WIDTH, .h = BAR_HEIGHT};
surface->drawRectBorder(&rect_wired, BAR_COLOR); surface->drawRectBorder(&rect_wired, BAR_COLOR);
// Draw progress bar fill // Draw progress bar fill
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * count_.getPercentage(); const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * count_.getPercentage();
SDL_FRect rect_full = {X_PADDING, BAR_POSITION, FULL_BAR_WIDTH, BAR_HEIGHT}; SDL_FRect rect_full = {.x = X_PADDING, .y = BAR_POSITION, .w = FULL_BAR_WIDTH, .h = BAR_HEIGHT};
surface->fillRect(&rect_full, BAR_COLOR); surface->fillRect(&rect_full, BAR_COLOR);
Screen::get()->render(); Screen::get()->render();

View File

@@ -19,11 +19,11 @@ namespace Resource {
// Singleton // Singleton
List* List::instance = nullptr; List* List::instance = nullptr;
void List::init(const std::string& executable_path) { void List::init(const std::string& executable_path) { // NOLINT(readability-convert-member-functions-to-static)
List::instance = new List(executable_path); List::instance = new List(executable_path);
} }
void List::destroy() { void List::destroy() { // NOLINT(readability-convert-member-functions-to-static)
delete List::instance; delete List::instance;
} }
@@ -32,12 +32,12 @@ namespace Resource {
} }
// Añade un elemento al mapa (función auxiliar) // Añade un elemento al mapa (función auxiliar)
void List::addToMap(const std::string& file_path, Type type, bool required, bool absolute) { void List::addToMap(const std::string& file_path, Type type, bool required, bool absolute) { // NOLINT(readability-convert-member-functions-to-static)
std::string full_path = absolute ? file_path : executable_path_ + file_path; std::string full_path = absolute ? file_path : executable_path_ + file_path;
std::string filename = getFileName(full_path); std::string filename = getFileName(full_path);
// Verificar si ya existe el archivo // Verificar si ya existe el archivo
if (file_list_.find(filename) != file_list_.end()) { if (file_list_.contains(filename)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Warning: Asset '%s' already exists, overwriting", "Warning: Asset '%s' already exists, overwriting",
filename.c_str()); filename.c_str());
@@ -52,7 +52,7 @@ namespace Resource {
} }
// Carga recursos desde un archivo de configuración con soporte para variables // 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) { void List::loadFromFile(const std::string& config_file_path, const std::string& prefix, const std::string& system_folder) { // NOLINT(readability-convert-member-functions-to-static)
std::ifstream file(config_file_path); std::ifstream file(config_file_path);
if (!file.is_open()) { if (!file.is_open()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
@@ -71,7 +71,7 @@ namespace Resource {
} }
// Carga recursos desde un string de configuración (para release con pack) // 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) { void List::loadFromString(const std::string& config_content, const std::string& prefix, const std::string& system_folder) { // NOLINT(readability-convert-member-functions-to-static)
try { try {
// Parsear YAML // Parsear YAML
auto yaml = fkyaml::node::deserialize(config_content); auto yaml = fkyaml::node::deserialize(config_content);
@@ -156,7 +156,7 @@ namespace Resource {
} }
// Devuelve la ruta completa a un fichero (búsqueda O(1)) // Devuelve la ruta completa a un fichero (búsqueda O(1))
auto List::get(const std::string& filename) const -> std::string { auto List::get(const std::string& filename) const -> std::string { // NOLINT(readability-convert-member-functions-to-static)
auto it = file_list_.find(filename); auto it = file_list_.find(filename);
if (it != file_list_.end()) { if (it != file_list_.end()) {
return it->second.file; return it->second.file;
@@ -167,7 +167,7 @@ namespace Resource {
} }
// Carga datos del archivo // Carga datos del archivo
auto List::loadData(const std::string& filename) const -> std::vector<uint8_t> { auto List::loadData(const std::string& filename) const -> std::vector<uint8_t> { // NOLINT(readability-convert-member-functions-to-static)
auto it = file_list_.find(filename); auto it = file_list_.find(filename);
if (it != file_list_.end()) { if (it != file_list_.end()) {
std::ifstream file(it->second.file, std::ios::binary); std::ifstream file(it->second.file, std::ios::binary);
@@ -197,11 +197,11 @@ namespace Resource {
// Verifica si un recurso existe // Verifica si un recurso existe
auto List::exists(const std::string& filename) const -> bool { auto List::exists(const std::string& filename) const -> bool {
return file_list_.find(filename) != file_list_.end(); return file_list_.contains(filename);
} }
// Parsea string a Type // Parsea string a Type
auto List::parseAssetType(const std::string& type_str) -> Type { auto List::parseAssetType(const std::string& type_str) -> Type { // NOLINT(readability-convert-member-functions-to-static)
if (type_str == "DATA") { if (type_str == "DATA") {
return Type::DATA; return Type::DATA;
} }
@@ -235,7 +235,7 @@ namespace Resource {
} }
// Devuelve el nombre del tipo de recurso // Devuelve el nombre del tipo de recurso
auto List::getTypeName(Type type) -> std::string { auto List::getTypeName(Type type) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
switch (type) { switch (type) {
case Type::DATA: case Type::DATA:
return "DATA"; return "DATA";
@@ -259,7 +259,7 @@ namespace Resource {
} }
// Devuelve la lista de recursos de un tipo // Devuelve la lista de recursos de un tipo
auto List::getListByType(Type type) const -> std::vector<std::string> { auto List::getListByType(Type type) const -> std::vector<std::string> { // NOLINT(readability-convert-member-functions-to-static)
std::vector<std::string> list; std::vector<std::string> list;
for (const auto& [filename, item] : file_list_) { for (const auto& [filename, item] : file_list_) {
@@ -275,7 +275,7 @@ namespace Resource {
} }
// Reemplaza variables en las rutas // Reemplaza variables en las rutas
auto List::replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string { auto List::replaceVariables(const std::string& path, const std::string& prefix, const std::string& system_folder) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
std::string result = path; std::string result = path;
// Reemplazar ${PREFIX} // Reemplazar ${PREFIX}
@@ -296,7 +296,7 @@ namespace Resource {
} }
// Parsea las opciones de una línea de configuración // Parsea las opciones de una línea de configuración
auto List::parseOptions(const std::string& options, bool& required, bool& absolute) -> void { auto List::parseOptions(const std::string& options, bool& required, bool& absolute) -> void { // NOLINT(readability-convert-member-functions-to-static)
if (options.empty()) { if (options.empty()) {
return; return;
} }

View File

@@ -53,7 +53,7 @@ namespace Resource {
} }
// Load a resource // Load a resource
auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> { auto Loader::loadResource(const std::string& filename) -> std::vector<uint8_t> { // NOLINT(readability-make-member-function-const)
if (!initialized_) { if (!initialized_) {
std::cerr << "Loader: Not initialized\n"; std::cerr << "Loader: Not initialized\n";
return {}; return {};
@@ -81,7 +81,7 @@ namespace Resource {
} }
// Check if a resource exists // Check if a resource exists
auto Loader::resourceExists(const std::string& filename) -> bool { auto Loader::resourceExists(const std::string& filename) -> bool { // NOLINT(readability-make-member-function-const)
if (!initialized_) { if (!initialized_) {
return false; return false;
} }
@@ -107,7 +107,7 @@ namespace Resource {
} }
// Get pack statistics // Get pack statistics
auto Loader::getPackResourceCount() const -> size_t { auto Loader::getPackResourceCount() const -> size_t { // NOLINT(readability-convert-member-functions-to-static)
if (resource_pack_ && resource_pack_->isLoaded()) { if (resource_pack_ && resource_pack_->isLoaded()) {
return resource_pack_->getResourceCount(); return resource_pack_->getResourceCount();
} }
@@ -122,7 +122,7 @@ namespace Resource {
} }
// Load from filesystem // Load from filesystem
auto Loader::loadFromFilesystem(const std::string& filepath) auto Loader::loadFromFilesystem(const std::string& filepath) // NOLINT(readability-convert-member-functions-to-static)
-> std::vector<uint8_t> { -> std::vector<uint8_t> {
std::ifstream file(filepath, std::ios::binary | std::ios::ate); std::ifstream file(filepath, std::ios::binary | std::ios::ate);
if (!file) { if (!file) {
@@ -147,7 +147,7 @@ namespace Resource {
} }
// Validate pack integrity // Validate pack integrity
auto Loader::validatePack() const -> bool { auto Loader::validatePack() const -> bool { // NOLINT(readability-convert-member-functions-to-static)
if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) { if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
std::cerr << "Loader: Cannot validate - pack not loaded\n"; std::cerr << "Loader: Cannot validate - pack not loaded\n";
return false; return false;
@@ -158,7 +158,7 @@ namespace Resource {
if (checksum == 0) { if (checksum == 0) {
std::cerr << "Loader: Pack checksum is zero (invalid)\n"; std::cerr << "Loader: Pack checksum is zero (invalid)\n";
return false; return false; // NOLINT(readability-simplify-boolean-expr)
} }
std::cout << "Loader: Pack checksum: 0x" << std::hex << checksum << std::dec std::cout << "Loader: Pack checksum: 0x" << std::hex << checksum << std::dec
@@ -168,7 +168,7 @@ namespace Resource {
} }
// Load assets.yaml from pack // Load assets.yaml from pack
auto Loader::loadAssetsConfig() const -> std::string { auto Loader::loadAssetsConfig() const -> std::string { // NOLINT(readability-convert-member-functions-to-static)
if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) { if (!initialized_ || !resource_pack_ || !resource_pack_->isLoaded()) {
std::cerr << "Loader: Cannot load assets config - pack not loaded\n"; std::cerr << "Loader: Cannot load assets config - pack not loaded\n";
return ""; return "";

View File

@@ -13,7 +13,7 @@
namespace Resource { namespace Resource {
// Calculate CRC32 checksum for data verification // Calculate CRC32 checksum for data verification
auto Pack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t { auto Pack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t { // NOLINT(readability-convert-member-functions-to-static)
uint32_t checksum = 0x12345678; uint32_t checksum = 0x12345678;
for (unsigned char byte : data) { for (unsigned char byte : data) {
checksum = ((checksum << 5) + checksum) + byte; checksum = ((checksum << 5) + checksum) + byte;
@@ -22,7 +22,7 @@ namespace Resource {
} }
// XOR encryption (symmetric - same function for encrypt/decrypt) // XOR encryption (symmetric - same function for encrypt/decrypt)
void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) { void Pack::encryptData(std::vector<uint8_t>& data, const std::string& key) { // NOLINT(readability-identifier-naming)
if (key.empty()) { if (key.empty()) {
return; return;
} }
@@ -31,13 +31,13 @@ namespace Resource {
} }
} }
void Pack::decryptData(std::vector<uint8_t>& data, const std::string& key) { void Pack::decryptData(std::vector<uint8_t>& data, const std::string& key) { // NOLINT(readability-identifier-naming)
// XOR is symmetric // XOR is symmetric
encryptData(data, key); encryptData(data, key);
} }
// Read entire file into memory // Read entire file into memory
auto Pack::readFile(const std::string& filepath) -> std::vector<uint8_t> { auto Pack::readFile(const std::string& filepath) -> std::vector<uint8_t> { // NOLINT(readability-convert-member-functions-to-static)
std::ifstream file(filepath, std::ios::binary | std::ios::ate); std::ifstream file(filepath, std::ios::binary | std::ios::ate);
if (!file) { if (!file) {
std::cerr << "ResourcePack: Failed to open file: " << filepath << '\n'; std::cerr << "ResourcePack: Failed to open file: " << filepath << '\n';
@@ -57,7 +57,7 @@ namespace Resource {
} }
// Add a single file to the pack // Add a single file to the pack
auto Pack::addFile(const std::string& filepath, const std::string& pack_name) auto Pack::addFile(const std::string& filepath, const std::string& pack_name) // NOLINT(readability-convert-member-functions-to-static)
-> bool { -> bool {
auto file_data = readFile(filepath); auto file_data = readFile(filepath);
if (file_data.empty()) { if (file_data.empty()) {
@@ -80,9 +80,9 @@ namespace Resource {
} }
// Add all files from a directory recursively // Add all files from a directory recursively
auto Pack::addDirectory(const std::string& dir_path, auto Pack::addDirectory(const std::string& dir_path, // NOLINT(readability-convert-member-functions-to-static)
const std::string& base_path) -> bool { const std::string& base_path) -> bool {
namespace fs = std::filesystem; namespace fs = std::filesystem; // NOLINT(readability-identifier-naming)
if (!fs::exists(dir_path) || !fs::is_directory(dir_path)) { if (!fs::exists(dir_path) || !fs::is_directory(dir_path)) {
std::cerr << "ResourcePack: Directory not found: " << dir_path << '\n'; std::cerr << "ResourcePack: Directory not found: " << dir_path << '\n';
@@ -117,7 +117,7 @@ namespace Resource {
} }
// Save the pack to a file // Save the pack to a file
auto Pack::savePack(const std::string& pack_file) -> bool { auto Pack::savePack(const std::string& pack_file) -> bool { // NOLINT(readability-convert-member-functions-to-static)
std::ofstream file(pack_file, std::ios::binary); std::ofstream file(pack_file, std::ios::binary);
if (!file) { if (!file) {
std::cerr << "ResourcePack: Failed to create pack file: " << pack_file << '\n'; std::cerr << "ResourcePack: Failed to create pack file: " << pack_file << '\n';
@@ -229,7 +229,7 @@ namespace Resource {
} }
// Get a resource by name // Get a resource by name
auto Pack::getResource(const std::string& filename) -> std::vector<uint8_t> { auto Pack::getResource(const std::string& filename) -> std::vector<uint8_t> { // NOLINT(readability-convert-member-functions-to-static)
auto it = resources_.find(filename); auto it = resources_.find(filename);
if (it == resources_.end()) { if (it == resources_.end()) {
return {}; return {};
@@ -259,11 +259,11 @@ namespace Resource {
// Check if a resource exists // Check if a resource exists
auto Pack::hasResource(const std::string& filename) const -> bool { auto Pack::hasResource(const std::string& filename) const -> bool {
return resources_.find(filename) != resources_.end(); return resources_.contains(filename);
} }
// Get list of all resources // Get list of all resources
auto Pack::getResourceList() const -> std::vector<std::string> { auto Pack::getResourceList() const -> std::vector<std::string> { // NOLINT(readability-convert-member-functions-to-static)
std::vector<std::string> list; std::vector<std::string> list;
list.reserve(resources_.size()); list.reserve(resources_.size());
for (const auto& [name, entry] : resources_) { for (const auto& [name, entry] : resources_) {
@@ -274,7 +274,7 @@ namespace Resource {
} }
// Calculate overall pack checksum for validation // Calculate overall pack checksum for validation
auto Pack::calculatePackChecksum() const -> uint32_t { auto Pack::calculatePackChecksum() const -> uint32_t { // NOLINT(readability-convert-member-functions-to-static)
if (!loaded_ || data_.empty()) { if (!loaded_ || data_.empty()) {
return 0; return 0;
} }

View File

@@ -40,13 +40,13 @@ namespace Resource {
auto loadPack(const std::string& pack_file) -> bool; auto loadPack(const std::string& pack_file) -> bool;
auto getResource(const std::string& filename) -> std::vector<uint8_t>; // Resource access auto getResource(const std::string& filename) -> std::vector<uint8_t>; // Resource access
auto hasResource(const std::string& filename) const -> bool; [[nodiscard]] auto hasResource(const std::string& filename) const -> bool;
auto getResourceList() const -> std::vector<std::string>; [[nodiscard]] auto getResourceList() const -> std::vector<std::string>;
auto isLoaded() const -> bool { return loaded_; } // Status queries [[nodiscard]] auto isLoaded() const -> bool { return loaded_; } // Status queries
auto getResourceCount() const -> size_t { return resources_.size(); } [[nodiscard]] auto getResourceCount() const -> size_t { return resources_.size(); }
auto getDataSize() const -> size_t { return data_.size(); } [[nodiscard]] auto getDataSize() const -> size_t { return data_.size(); }
auto calculatePackChecksum() const -> uint32_t; // Validation [[nodiscard]] auto calculatePackChecksum() const -> uint32_t; // Validation
private: private:
static constexpr std::array<char, 4> MAGIC_HEADER = {'J', 'D', 'D', 'I'}; // Pack format constants static constexpr std::array<char, 4> MAGIC_HEADER = {'J', 'D', 'D', 'I'}; // Pack format constants

View File

@@ -28,7 +28,7 @@ auto Debug::get() -> Debug* {
} }
// Dibuja en pantalla // Dibuja en pantalla
void Debug::render() { void Debug::render() { // NOLINT(readability-make-member-function-const)
auto text = Resource::Cache::get()->getText("aseprite"); auto text = Resource::Cache::get()->getText("aseprite");
int y = y_; int y = y_;
int w = 0; int w = 0;
@@ -39,7 +39,7 @@ void Debug::render() {
y += text->getCharacterSize() + 1; y += text->getCharacterSize() + 1;
if (y > 192 - text->getCharacterSize()) { if (y > 192 - text->getCharacterSize()) {
y = y_; y = y_;
x_ += w * text->getCharacterSize() + 2; x_ += (w * text->getCharacterSize()) + 2;
} }
} }

View File

@@ -120,11 +120,11 @@ Director::Director(std::vector<std::string> const& args) {
#endif #endif
// Configura la ruta y carga las opciones desde un fichero // Configura la ruta y carga las opciones desde un fichero
Options::setConfigFile(Resource::List::get()->get("config.yaml")); Options::setConfigFile(Resource::List::get()->get("config.yaml")); // NOLINT(readability-static-accessed-through-instance)
Options::loadFromFile(); Options::loadFromFile();
// Configura la ruta y carga los presets de PostFX // Configura la ruta y carga los presets de PostFX
Options::setPostFXFile(Resource::List::get()->get("postfx.yaml")); Options::setPostFXFile(Resource::List::get()->get("postfx.yaml")); // NOLINT(readability-static-accessed-through-instance)
Options::loadPostFXFromFile(); Options::loadPostFXFromFile();
// En mode quiosc, forçar pantalla completa independentment de la configuració // En mode quiosc, forçar pantalla completa independentment de la configuració
@@ -150,7 +150,7 @@ Director::Director(std::vector<std::string> const& args) {
Input::init(gamecontroller_db); Input::init(gamecontroller_db);
#else #else
// In development, use Asset as normal // In development, use Asset as normal
Input::init(Resource::List::get()->get("gamecontrollerdb.txt")); // Carga configuración de controles Input::init(Resource::List::get()->get("gamecontrollerdb.txt")); // NOLINT(readability-static-accessed-through-instance) Carga configuración de controles
#endif #endif
// Aplica las teclas y botones del gamepad configurados desde Options // Aplica las teclas y botones del gamepad configurados desde Options
@@ -168,7 +168,7 @@ Director::Director(std::vector<std::string> const& args) {
std::string locale_path = executable_path_ + PREFIX + "/data/locale/" + Options::language + ".yaml"; std::string locale_path = executable_path_ + PREFIX + "/data/locale/" + Options::language + ".yaml";
Locale::init(locale_path); Locale::init(locale_path);
#else #else
Locale::init(Resource::List::get()->get(Options::language + ".yaml")); Locale::init(Resource::List::get()->get(Options::language + ".yaml")); // NOLINT(readability-static-accessed-through-instance)
#endif #endif
// Special handling for cheevos.bin - also needs filesystem path // Special handling for cheevos.bin - also needs filesystem path
@@ -204,7 +204,7 @@ Director::~Director() {
} }
// Comprueba los parametros del programa // Comprueba los parametros del programa
auto Director::checkProgramArguments(std::vector<std::string> const& args) -> std::string { auto Director::checkProgramArguments(std::vector<std::string> const& args) -> std::string { // NOLINT(readability-identifier-naming)
// Iterar sobre los argumentos del programa (saltando args[0] que es el ejecutable) // Iterar sobre los argumentos del programa (saltando args[0] que es el ejecutable)
for (std::size_t i = 1; i < args.size(); ++i) { for (std::size_t i = 1; i < args.size(); ++i) {
const std::string& argument = args[i]; const std::string& argument = args[i];
@@ -226,7 +226,7 @@ auto Director::checkProgramArguments(std::vector<std::string> const& args) -> st
} }
// Crea la carpeta del sistema donde guardar datos // Crea la carpeta del sistema donde guardar datos
void Director::createSystemFolder(const std::string& folder) { void Director::createSystemFolder(const std::string& folder) { // NOLINT(readability-convert-member-functions-to-static)
#ifdef _WIN32 #ifdef _WIN32
system_folder_ = std::string(getenv("APPDATA")) + "/" + folder; system_folder_ = std::string(getenv("APPDATA")) + "/" + folder;
#elif __APPLE__ #elif __APPLE__
@@ -281,7 +281,7 @@ void Director::createSystemFolder(const std::string& folder) {
} }
// Carga la configuración de assets desde assets.yaml // Carga la configuración de assets desde assets.yaml
void Director::setFileList() { void Director::setFileList() { // NOLINT(readability-convert-member-functions-to-static)
// Determinar el prefijo de ruta según la plataforma // Determinar el prefijo de ruta según la plataforma
#ifdef MACOS_BUNDLE #ifdef MACOS_BUNDLE
const std::string PREFIX = "/../Resources"; const std::string PREFIX = "/../Resources";

View File

@@ -4,13 +4,13 @@
#include <cstdlib> // Para rand #include <cstdlib> // Para rand
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "utils/utils.hpp" // Para stringToColor #include "utils/utils.hpp" // Para stringToColor
// Constructor // Constructor
Enemy::Enemy(const Data& enemy) Enemy::Enemy(const Data& enemy)
: sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData(enemy.animation_path))), : sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData(enemy.animation_path))),
color_string_(enemy.color), color_string_(enemy.color),
x1_(enemy.x1), x1_(enemy.x1),
x2_(enemy.x2), x2_(enemy.x2),
@@ -49,7 +49,7 @@ void Enemy::update(float delta_time) {
} }
// Comprueba si ha llegado al limite del recorrido para darse media vuelta // Comprueba si ha llegado al limite del recorrido para darse media vuelta
void Enemy::checkPath() { void Enemy::checkPath() { // NOLINT(readability-make-member-function-const)
if (sprite_->getPosX() > x2_ || sprite_->getPosX() < x1_) { if (sprite_->getPosX() > x2_ || sprite_->getPosX() < x1_) {
// Recoloca // Recoloca
if (sprite_->getPosX() > x2_) { if (sprite_->getPosX() > x2_) {

View File

@@ -2,9 +2,9 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string #include <string> // Para string
class SurfaceAnimatedSprite; // lines 7-7 class AnimatedSprite; // lines 7-7
class Enemy { class Enemy {
public: public:
@@ -36,7 +36,7 @@ class Enemy {
private: private:
void checkPath(); // Comprueba si ha llegado al limite del recorrido para darse media vuelta void checkPath(); // Comprueba si ha llegado al limite del recorrido para darse media vuelta
std::shared_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del enemigo std::shared_ptr<AnimatedSprite> sprite_; // Sprite del enemigo
// Variables // Variables
Uint8 color_{0}; // Color del enemigo Uint8 color_{0}; // Color del enemigo

View File

@@ -1,11 +1,11 @@
#include "game/entities/item.hpp" #include "game/entities/item.hpp"
#include "core/rendering/surface_sprite.hpp" // Para SSprite #include "core/rendering/sprite/sprite.hpp" // Para SSprite
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
// Constructor // Constructor
Item::Item(const Data& item) Item::Item(const Data& item)
: sprite_(std::make_shared<SurfaceSprite>(Resource::Cache::get()->getSurface(item.tile_set_file), item.x, item.y, ITEM_SIZE, ITEM_SIZE)), : sprite_(std::make_shared<Sprite>(Resource::Cache::get()->getSurface(item.tile_set_file), item.x, item.y, ITEM_SIZE, ITEM_SIZE)),
time_accumulator_(static_cast<float>(item.counter) * COLOR_CHANGE_INTERVAL) { time_accumulator_(static_cast<float>(item.counter) * COLOR_CHANGE_INTERVAL) {
// Inicia variables // Inicia variables
sprite_->setClip((item.tile % 10) * ITEM_SIZE, (item.tile / 10) * ITEM_SIZE, ITEM_SIZE, ITEM_SIZE); sprite_->setClip((item.tile % 10) * ITEM_SIZE, (item.tile / 10) * ITEM_SIZE, ITEM_SIZE, ITEM_SIZE);
@@ -29,15 +29,15 @@ void Item::update(float delta_time) {
} }
// Pinta el objeto en pantalla // Pinta el objeto en pantalla
void Item::render() const { void Item::render() const { // NOLINT(readability-convert-member-functions-to-static)
// Calcula el índice de color basado en el tiempo acumulado // Calcula el índice de color basado en el tiempo acumulado
const int INDEX = static_cast<int>(time_accumulator_ / COLOR_CHANGE_INTERVAL) % static_cast<int>(color_.size()); const int INDEX = static_cast<int>(time_accumulator_ / COLOR_CHANGE_INTERVAL) % static_cast<int>(color_.size());
sprite_->render(1, color_.at(INDEX)); sprite_->render(1, color_.at(INDEX));
} }
// Obtiene su ubicación // Obtiene su ubicación
auto Item::getPos() -> SDL_FPoint { auto Item::getPos() -> SDL_FPoint { // NOLINT(readability-convert-member-functions-to-static)
const SDL_FPoint P = {sprite_->getX(), sprite_->getY()}; const SDL_FPoint P = {.x = sprite_->getX(), .y = sprite_->getY()};
return P; return P;
} }

View File

@@ -5,7 +5,7 @@
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
class SurfaceSprite; class Sprite;
class Item { class Item {
public: public:
@@ -34,7 +34,7 @@ class Item {
static constexpr float ITEM_SIZE = 8.0F; // Tamaño del item en pixels static constexpr float ITEM_SIZE = 8.0F; // Tamaño del item en pixels
static constexpr float COLOR_CHANGE_INTERVAL = 0.06F; // Intervalo de cambio de color en segundos (4 frames a 66.67fps) static constexpr float COLOR_CHANGE_INTERVAL = 0.06F; // Intervalo de cambio de color en segundos (4 frames a 66.67fps)
std::shared_ptr<SurfaceSprite> sprite_; // SSprite del objeto std::shared_ptr<Sprite> sprite_; // SSprite del objeto
// Variables // Variables
std::vector<Uint8> color_; // Vector con los colores del objeto std::vector<Uint8> color_; // Vector con los colores del objeto

View File

@@ -6,13 +6,13 @@
#include <iostream> #include <iostream>
#include <ranges> // Para std::ranges::any_of #include <ranges> // Para std::ranges::any_of
#include "core/audio/audio.hpp" // Para Audio #include "core/audio/audio.hpp" // Para Audio
#include "core/input/input.hpp" // Para Input, InputAction #include "core/input/input.hpp" // Para Input, InputAction
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "game/gameplay/room.hpp" // Para Room, TileType #include "game/gameplay/room.hpp" // Para Room, TileType
#include "game/options.hpp" // Para Cheat, Options, options #include "game/options.hpp" // Para Cheat, Options, options
#include "utils/defines.hpp" // Para RoomBorder::BOTTOM, RoomBorder::LEFT, RoomBorder::RIGHT #include "utils/defines.hpp" // Para RoomBorder::BOTTOM, RoomBorder::LEFT, RoomBorder::RIGHT
#ifdef _DEBUG #ifdef _DEBUG
#include "core/system/debug.hpp" // Para Debug #include "core/system/debug.hpp" // Para Debug
@@ -352,7 +352,7 @@ void Player::moveJumping(float delta_time) {
// Comprueba la colisión con las superficies y las cintas transportadoras (sin rampas) // Comprueba la colisión con las superficies y las cintas transportadoras (sin rampas)
// Extendemos 1px hacia arriba para detectar suelos traversados ligeramente al // Extendemos 1px hacia arriba para detectar suelos traversados ligeramente al
// entrar horizontalmente (consecuencia del margen h=HEIGHT-1 en la proyección horizontal) // entrar horizontalmente (consecuencia del margen h=HEIGHT-1 en la proyección horizontal)
const SDL_FRect ADJ = {PROJECTION.x, PROJECTION.y - 1.0F, PROJECTION.w, PROJECTION.h + 1.0F}; const SDL_FRect ADJ = {.x = PROJECTION.x, .y = PROJECTION.y - 1.0F, .w = PROJECTION.w, .h = PROJECTION.h + 1.0F};
const float POS = std::max(room_->checkTopSurfaces(ADJ), room_->checkAutoSurfaces(ADJ)); const float POS = std::max(room_->checkTopSurfaces(ADJ), room_->checkAutoSurfaces(ADJ));
if (POS != Collision::NONE) { if (POS != Collision::NONE) {
// Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie // Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie
@@ -445,7 +445,7 @@ void Player::applyGravity(float delta_time) {
} }
// Establece la animación del jugador // Establece la animación del jugador
void Player::animate(float delta_time) { void Player::animate(float delta_time) { // NOLINT(readability-make-member-function-const)
if (vx_ != 0) { if (vx_ != 0) {
sprite_->update(delta_time); sprite_->update(delta_time);
} }
@@ -461,7 +461,7 @@ void Player::handleJumpEnd() {
} }
// Calcula y reproduce el sonido de salto basado en tiempo transcurrido // Calcula y reproduce el sonido de salto basado en tiempo transcurrido
void Player::playJumpSound(float delta_time) { void Player::playJumpSound(float delta_time) { // NOLINT(readability-convert-member-functions-to-static)
size_t sound_index; size_t sound_index;
if (jump_sound_ctrl_.shouldPlay(delta_time, sound_index)) { if (jump_sound_ctrl_.shouldPlay(delta_time, sound_index)) {
if (sound_index < jumping_sound_.size()) { if (sound_index < jumping_sound_.size()) {
@@ -471,7 +471,7 @@ void Player::playJumpSound(float delta_time) {
} }
// Calcula y reproduce el sonido de caída basado en distancia vertical recorrida // Calcula y reproduce el sonido de caída basado en distancia vertical recorrida
void Player::playFallSound(float delta_time) { void Player::playFallSound(float delta_time) { // NOLINT(readability-convert-member-functions-to-static)
size_t sound_index; size_t sound_index;
if (fall_sound_ctrl_.shouldPlay(delta_time, y_, sound_index)) { if (fall_sound_ctrl_.shouldPlay(delta_time, y_, sound_index)) {
if (sound_index < falling_sound_.size()) { if (sound_index < falling_sound_.size()) {
@@ -593,7 +593,7 @@ void Player::updateCurrentSlope() {
// Comprueba que el jugador no toque ningun tile de los que matan // Comprueba que el jugador no toque ningun tile de los que matan
auto Player::handleKillingTiles() -> bool { auto Player::handleKillingTiles() -> bool {
// Comprueba si hay contacto con algún tile que mata // Comprueba si hay contacto con algún tile que mata
if (std::ranges::any_of(collider_points_, [this](const auto& c) { if (std::ranges::any_of(collider_points_, [this](const auto& c) -> bool {
return room_->getTile(c) == Room::Tile::KILL; return room_->getTile(c) == Room::Tile::KILL;
})) { })) {
markAsDead(); // Mata al jugador inmediatamente markAsDead(); // Mata al jugador inmediatamente
@@ -643,7 +643,7 @@ void Player::updateFeet() {
} }
// Inicializa los sonidos de salto y caida // Inicializa los sonidos de salto y caida
void Player::initSounds() { void Player::initSounds() { // NOLINT(readability-convert-member-functions-to-static)
for (int i = 0; i < 24; ++i) { for (int i = 0; i < 24; ++i) {
std::string sound_file = "jump" + std::to_string(i + 1) + ".wav"; std::string sound_file = "jump" + std::to_string(i + 1) + ".wav";
jumping_sound_[i] = Resource::Cache::get()->getSound(sound_file); jumping_sound_[i] = Resource::Cache::get()->getSound(sound_file);
@@ -678,14 +678,14 @@ auto Player::JumpSoundController::shouldPlay(float delta_time, size_t& out_index
elapsed_time += delta_time; elapsed_time += delta_time;
// Calcula qué sonido debería estar sonando según el tiempo // Calcula qué sonido debería estar sonando según el tiempo
size_t target_index = FIRST_SOUND + static_cast<size_t>(elapsed_time / SECONDS_PER_SOUND); size_t target_index = FIRST_SOUND + static_cast<size_t>((elapsed_time / SECONDS_PER_SOUND));
target_index = std::min(target_index, LAST_SOUND); target_index = std::min(target_index, LAST_SOUND);
// Reproduce si hemos avanzado a un nuevo sonido // Reproduce si hemos avanzado a un nuevo sonido
if (target_index > current_index) { if (target_index > current_index) {
current_index = target_index; current_index = target_index;
out_index = current_index; out_index = current_index;
return true; return true; // NOLINT(readability-simplify-boolean-expr)
} }
return false; return false;
@@ -721,7 +721,7 @@ auto Player::FallSoundController::shouldPlay(float delta_time, float current_y,
last_y = current_y; last_y = current_y;
// Calcula qué sonido debería estar sonando según el intervalo // Calcula qué sonido debería estar sonando según el intervalo
size_t target_index = FIRST_SOUND + static_cast<size_t>(distance_traveled / PIXELS_PER_SOUND); size_t target_index = FIRST_SOUND + static_cast<size_t>((distance_traveled / PIXELS_PER_SOUND));
// El sonido a reproducir se limita a LAST_SOUND (13), pero el índice interno sigue creciendo // El sonido a reproducir se limita a LAST_SOUND (13), pero el índice interno sigue creciendo
size_t sound_to_play = std::min(target_index, LAST_SOUND); size_t sound_to_play = std::min(target_index, LAST_SOUND);
@@ -749,9 +749,9 @@ void Player::applySpawnValues(const SpawnData& spawn) {
} }
// Inicializa el sprite del jugador // Inicializa el sprite del jugador
void Player::initSprite(const std::string& animations_path) { void Player::initSprite(const std::string& animations_path) { // NOLINT(readability-convert-member-functions-to-static)
const auto& animation_data = Resource::Cache::get()->getAnimationData(animations_path); const auto& animation_data = Resource::Cache::get()->getAnimationData(animations_path);
sprite_ = std::make_unique<SurfaceAnimatedSprite>(animation_data); sprite_ = std::make_unique<AnimatedSprite>(animation_data);
sprite_->setWidth(WIDTH); sprite_->setWidth(WIDTH);
sprite_->setHeight(HEIGHT); sprite_->setHeight(HEIGHT);
sprite_->setCurrentAnimation("walk"); sprite_->setCurrentAnimation("walk");
@@ -865,7 +865,7 @@ void Player::resetSoundControllersOnLanding() {
} }
// Devuelve el rectangulo de proyeccion // Devuelve el rectangulo de proyeccion
auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect { auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect { // NOLINT(readability-convert-member-functions-to-static)
switch (direction) { switch (direction) {
case Direction::LEFT: case Direction::LEFT:
return { return {

View File

@@ -8,7 +8,7 @@
#include <string> // Para string #include <string> // Para string
#include <utility> #include <utility>
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "game/gameplay/room.hpp" #include "game/gameplay/room.hpp"
#include "game/options.hpp" // Para Cheat, Options, options #include "game/options.hpp" // Para Cheat, Options, options
#include "utils/defines.hpp" // Para BORDER_TOP, BLOCK #include "utils/defines.hpp" // Para BORDER_TOP, BLOCK
@@ -96,7 +96,7 @@ class Player {
[[nodiscard]] auto isOnBorder() const -> bool { return border_ != Room::Border::NONE; } // Indica si el jugador esta en uno de los cuatro bordes de la pantalla [[nodiscard]] auto isOnBorder() const -> bool { return border_ != Room::Border::NONE; } // Indica si el jugador esta en uno de los cuatro bordes de la pantalla
[[nodiscard]] auto getBorder() const -> Room::Border { return border_; } // Indica en cual de los cuatro bordes se encuentra [[nodiscard]] auto getBorder() const -> Room::Border { return border_; } // Indica en cual de los cuatro bordes se encuentra
void switchBorders(); // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla void switchBorders(); // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
auto getRect() -> SDL_FRect { return {x_, y_, WIDTH, HEIGHT}; } // Obtiene el rectangulo que delimita al jugador auto getRect() -> SDL_FRect { return {.x = x_, .y = y_, .w = WIDTH, .h = HEIGHT}; } // Obtiene el rectangulo que delimita al jugador
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats) void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats)
@@ -118,8 +118,8 @@ class Player {
static constexpr int MAX_FALLING_HEIGHT = Tile::SIZE * 4; // Altura maxima permitida de caída en pixels static constexpr int MAX_FALLING_HEIGHT = Tile::SIZE * 4; // Altura maxima permitida de caída en pixels
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
std::unique_ptr<SurfaceAnimatedSprite> sprite_; // Sprite del jugador std::unique_ptr<AnimatedSprite> sprite_; // Sprite del jugador
// --- Variables de posición y física --- // --- Variables de posición y física ---
float x_ = 0.0F; // Posición del jugador en el eje X float x_ = 0.0F; // Posición del jugador en el eje X
@@ -136,11 +136,11 @@ class Player {
State previous_state_ = State::ON_GROUND; // Estado previo en el que se encontraba el jugador State previous_state_ = State::ON_GROUND; // Estado previo en el que se encontraba el jugador
// --- Variables de colisión --- // --- Variables de colisión ---
SDL_FRect collider_box_{}; // Caja de colisión con los enemigos u objetos SDL_FRect collider_box_{}; // Caja de colisión con los enemigos u objetos
std::array<SDL_FPoint, 8> collider_points_{}; // Puntos de colisión con el mapa std::array<SDL_FPoint, 8> collider_points_{}; // Puntos de colisión con el mapa
SDL_FPoint under_left_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior izquierda del jugador SDL_FPoint under_left_foot_ = {.x = 0.0F, .y = 0.0F}; // El punto bajo la esquina inferior izquierda del jugador
SDL_FPoint under_right_foot_ = {0.0F, 0.0F}; // El punto bajo la esquina inferior derecha del jugador SDL_FPoint under_right_foot_ = {.x = 0.0F, .y = 0.0F}; // El punto bajo la esquina inferior derecha del jugador
const LineDiagonal* current_slope_{nullptr}; // Rampa actual sobe la que está el jugador const LineDiagonal* current_slope_{nullptr}; // Rampa actual sobe la que está el jugador
// --- Variables de juego --- // --- Variables de juego ---
bool is_alive_ = true; // Indica si el jugador esta vivo o no bool is_alive_ = true; // Indica si el jugador esta vivo o no

View File

@@ -16,7 +16,7 @@
Cheevos* Cheevos::cheevos = nullptr; Cheevos* Cheevos::cheevos = nullptr;
// [SINGLETON] Crearemos el objeto con esta función estática // [SINGLETON] Crearemos el objeto con esta función estática
void Cheevos::init(const std::string& file) { void Cheevos::init(const std::string& file) { // NOLINT(readability-convert-member-functions-to-static)
Cheevos::cheevos = new Cheevos(file); Cheevos::cheevos = new Cheevos(file);
} }
@@ -43,7 +43,7 @@ Cheevos::~Cheevos() {
} }
// Inicializa los logros // Inicializa los logros
void Cheevos::init() { void Cheevos::init() { // NOLINT(readability-convert-member-functions-to-static)
cheevos_list_.clear(); cheevos_list_.clear();
auto* loc = Locale::get(); auto* loc = Locale::get();
cheevos_list_.emplace_back(Achievement{.id = 1, .caption = loc->get("achievements.c1"), .description = loc->get("achievements.d1"), .icon = 2}); cheevos_list_.emplace_back(Achievement{.id = 1, .caption = loc->get("achievements.c1"), .description = loc->get("achievements.d1"), .icon = 2});
@@ -61,7 +61,7 @@ void Cheevos::init() {
} }
// Busca un logro por id y devuelve el indice // Busca un logro por id y devuelve el indice
auto Cheevos::find(int id) -> int { auto Cheevos::find(int id) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (int i = 0; i < (int)cheevos_list_.size(); ++i) { for (int i = 0; i < (int)cheevos_list_.size(); ++i) {
if (cheevos_list_[i].id == id) { if (cheevos_list_[i].id == id) {
return i; return i;
@@ -101,7 +101,7 @@ void Cheevos::setUnobtainable(int id) {
} }
// Carga el estado de los logros desde un fichero // Carga el estado de los logros desde un fichero
void Cheevos::loadFromFile() { void Cheevos::loadFromFile() { // NOLINT(readability-convert-member-functions-to-static)
std::ifstream file(file_, std::ios::binary); std::ifstream file(file_, std::ios::binary);
// El fichero no existe // El fichero no existe
@@ -162,7 +162,7 @@ void Cheevos::saveToFile() {
// Devuelve el número total de logros desbloqueados // Devuelve el número total de logros desbloqueados
auto Cheevos::getTotalUnlockedAchievements() -> int { auto Cheevos::getTotalUnlockedAchievements() -> int {
return std::count_if(cheevos_list_.begin(), cheevos_list_.end(), [](const auto& cheevo) { return cheevo.completed; }); return std::count_if(cheevos_list_.begin(), cheevos_list_.end(), [](const auto& cheevo) -> bool { return cheevo.completed; });
} }
// Elimina el estado "no obtenible" // Elimina el estado "no obtenible"

View File

@@ -36,7 +36,7 @@ auto CollisionMap::getTile(SDL_FPoint point) const -> Tile {
} }
// Devuelve el tipo de tile que hay en ese indice // Devuelve el tipo de tile que hay en ese indice
auto CollisionMap::getTile(int index) const -> Tile { auto CollisionMap::getTile(int index) const -> Tile { // NOLINT(readability-convert-member-functions-to-static)
const bool ON_RANGE = (index > -1) && (index < (int)tile_map_.size()); const bool ON_RANGE = (index > -1) && (index < (int)tile_map_.size());
if (ON_RANGE) { if (ON_RANGE) {
@@ -107,7 +107,7 @@ auto CollisionMap::getSlopeHeight(SDL_FPoint p, Tile slope) -> int {
// === Queries de colisión === // === Queries de colisión ===
// Comprueba las colisiones con paredes derechas // Comprueba las colisiones con paredes derechas
auto CollisionMap::checkRightSurfaces(const SDL_FRect& rect) -> int { auto CollisionMap::checkRightSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& s : right_walls_) { for (const auto& s : right_walls_) {
if (checkCollision(s, rect)) { if (checkCollision(s, rect)) {
return s.x; return s.x;
@@ -117,7 +117,7 @@ auto CollisionMap::checkRightSurfaces(const SDL_FRect& rect) -> int {
} }
// Comprueba las colisiones con paredes izquierdas // Comprueba las colisiones con paredes izquierdas
auto CollisionMap::checkLeftSurfaces(const SDL_FRect& rect) -> int { auto CollisionMap::checkLeftSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& s : left_walls_) { for (const auto& s : left_walls_) {
if (checkCollision(s, rect)) { if (checkCollision(s, rect)) {
return s.x; return s.x;
@@ -127,7 +127,7 @@ auto CollisionMap::checkLeftSurfaces(const SDL_FRect& rect) -> int {
} }
// Comprueba las colisiones con techos // Comprueba las colisiones con techos
auto CollisionMap::checkTopSurfaces(const SDL_FRect& rect) -> int { auto CollisionMap::checkTopSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& s : top_floors_) { for (const auto& s : top_floors_) {
if (checkCollision(s, rect)) { if (checkCollision(s, rect)) {
return s.y; return s.y;
@@ -138,13 +138,13 @@ auto CollisionMap::checkTopSurfaces(const SDL_FRect& rect) -> int {
// Comprueba las colisiones punto con techos // Comprueba las colisiones punto con techos
auto CollisionMap::checkTopSurfaces(const SDL_FPoint& p) -> bool { auto CollisionMap::checkTopSurfaces(const SDL_FPoint& p) -> bool {
return std::ranges::any_of(top_floors_, [&](const auto& s) { return std::ranges::any_of(top_floors_, [&](const auto& s) -> bool {
return checkCollision(s, p); return checkCollision(s, p);
}); });
} }
// Comprueba las colisiones con suelos // Comprueba las colisiones con suelos
auto CollisionMap::checkBottomSurfaces(const SDL_FRect& rect) -> int { auto CollisionMap::checkBottomSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& s : bottom_floors_) { for (const auto& s : bottom_floors_) {
if (checkCollision(s, rect)) { if (checkCollision(s, rect)) {
return s.y; return s.y;
@@ -154,7 +154,7 @@ auto CollisionMap::checkBottomSurfaces(const SDL_FRect& rect) -> int {
} }
// Comprueba las colisiones con conveyor belts // Comprueba las colisiones con conveyor belts
auto CollisionMap::checkAutoSurfaces(const SDL_FRect& rect) -> int { auto CollisionMap::checkAutoSurfaces(const SDL_FRect& rect) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& s : conveyor_belt_floors_) { for (const auto& s : conveyor_belt_floors_) {
if (checkCollision(s, rect)) { if (checkCollision(s, rect)) {
return s.y; return s.y;
@@ -165,13 +165,13 @@ auto CollisionMap::checkAutoSurfaces(const SDL_FRect& rect) -> int {
// Comprueba las colisiones punto con conveyor belts // Comprueba las colisiones punto con conveyor belts
auto CollisionMap::checkConveyorBelts(const SDL_FPoint& p) -> bool { auto CollisionMap::checkConveyorBelts(const SDL_FPoint& p) -> bool {
return std::ranges::any_of(conveyor_belt_floors_, [&](const auto& s) { return std::ranges::any_of(conveyor_belt_floors_, [&](const auto& s) -> bool {
return checkCollision(s, p); return checkCollision(s, p);
}); });
} }
// Comprueba las colisiones línea con rampas izquierdas // Comprueba las colisiones línea con rampas izquierdas
auto CollisionMap::checkLeftSlopes(const LineVertical& line) -> int { auto CollisionMap::checkLeftSlopes(const LineVertical& line) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& slope : left_slopes_) { for (const auto& slope : left_slopes_) {
const auto P = checkCollision(slope, line); const auto P = checkCollision(slope, line);
if (P.x != -1) { if (P.x != -1) {
@@ -183,13 +183,13 @@ auto CollisionMap::checkLeftSlopes(const LineVertical& line) -> int {
// Comprueba las colisiones punto con rampas izquierdas // Comprueba las colisiones punto con rampas izquierdas
auto CollisionMap::checkLeftSlopes(const SDL_FPoint& p) -> bool { auto CollisionMap::checkLeftSlopes(const SDL_FPoint& p) -> bool {
return std::ranges::any_of(left_slopes_, [&](const auto& slope) { return std::ranges::any_of(left_slopes_, [&](const auto& slope) -> bool {
return checkCollision(p, slope); return checkCollision(p, slope);
}); });
} }
// Comprueba las colisiones línea con rampas derechas // Comprueba las colisiones línea con rampas derechas
auto CollisionMap::checkRightSlopes(const LineVertical& line) -> int { auto CollisionMap::checkRightSlopes(const LineVertical& line) -> int { // NOLINT(readability-convert-member-functions-to-static)
for (const auto& slope : right_slopes_) { for (const auto& slope : right_slopes_) {
const auto P = checkCollision(slope, line); const auto P = checkCollision(slope, line);
if (P.x != -1) { if (P.x != -1) {
@@ -201,13 +201,13 @@ auto CollisionMap::checkRightSlopes(const LineVertical& line) -> int {
// Comprueba las colisiones punto con rampas derechas // Comprueba las colisiones punto con rampas derechas
auto CollisionMap::checkRightSlopes(const SDL_FPoint& p) -> bool { auto CollisionMap::checkRightSlopes(const SDL_FPoint& p) -> bool {
return std::ranges::any_of(right_slopes_, [&](const auto& slope) { return std::ranges::any_of(right_slopes_, [&](const auto& slope) -> bool {
return checkCollision(p, slope); return checkCollision(p, slope);
}); });
} }
// Obtiene puntero a slope en un punto (prioriza left_slopes_ sobre right_slopes_) // Obtiene puntero a slope en un punto (prioriza left_slopes_ sobre right_slopes_)
auto CollisionMap::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* { auto CollisionMap::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* { // NOLINT(readability-convert-member-functions-to-static)
// Primero busca en rampas izquierdas // Primero busca en rampas izquierdas
for (const auto& slope : left_slopes_) { for (const auto& slope : left_slopes_) {
if (checkCollision(p, slope)) { if (checkCollision(p, slope)) {
@@ -229,7 +229,7 @@ auto CollisionMap::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiago
// === Helpers para recopilar tiles === // === Helpers para recopilar tiles ===
// Helper: recopila tiles inferiores (muros sin muro debajo) // Helper: recopila tiles inferiores (muros sin muro debajo)
auto CollisionMap::collectBottomTiles() -> std::vector<int> { auto CollisionMap::collectBottomTiles() -> std::vector<int> { // NOLINT(readability-make-member-function-const)
std::vector<int> tile; std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tengan debajo otro muro // Busca todos los tiles de tipo muro que no tengan debajo otro muro
@@ -251,7 +251,7 @@ auto CollisionMap::collectBottomTiles() -> std::vector<int> {
} }
// Helper: recopila tiles superiores (muros o pasables sin muro encima) // Helper: recopila tiles superiores (muros o pasables sin muro encima)
auto CollisionMap::collectTopTiles() -> std::vector<int> { auto CollisionMap::collectTopTiles() -> std::vector<int> { // NOLINT(readability-make-member-function-const)
std::vector<int> tile; std::vector<int> tile;
// Busca todos los tiles de tipo muro o pasable que no tengan encima un muro // Busca todos los tiles de tipo muro o pasable que no tengan encima un muro
@@ -273,7 +273,7 @@ auto CollisionMap::collectTopTiles() -> std::vector<int> {
} }
// Helper: recopila tiles animados (para superficies automaticas/conveyor belts) // Helper: recopila tiles animados (para superficies automaticas/conveyor belts)
auto CollisionMap::collectAnimatedTiles() -> std::vector<int> { auto CollisionMap::collectAnimatedTiles() -> std::vector<int> { // NOLINT(readability-make-member-function-const)
std::vector<int> tile; std::vector<int> tile;
// Busca todos los tiles de tipo animado // Busca todos los tiles de tipo animado
@@ -298,13 +298,13 @@ auto CollisionMap::collectAnimatedTiles() -> std::vector<int> {
} }
// Helper: construye lineas horizontales a partir de tiles consecutivos // Helper: construye lineas horizontales a partir de tiles consecutivos
void CollisionMap::buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface) { void CollisionMap::buildHorizontalLines(const std::vector<int>& tiles, std::vector<LineHorizontal>& lines, bool is_bottom_surface) { // NOLINT(readability-convert-member-functions-to-static)
if (tiles.size() <= 1) { if (tiles.size() <= 1) {
return; return;
} }
int i = 0; int i = 0;
while (i < (int)tiles.size() - 1) { while (i < static_cast<int>(tiles.size()) - 1) {
LineHorizontal line; LineHorizontal line;
line.x1 = (tiles[i] % MAP_WIDTH) * TILE_SIZE; line.x1 = (tiles[i] % MAP_WIDTH) * TILE_SIZE;
@@ -319,11 +319,11 @@ void CollisionMap::buildHorizontalLines(const std::vector<int>& tiles, std::vect
i++; i++;
// Encuentra tiles consecutivos // Encuentra tiles consecutivos
if (i < (int)tiles.size()) { if (i < static_cast<int>(tiles.size())) {
while (tiles[i] == tiles[i - 1] + 1) { while (tiles[i] == tiles[i - 1] + 1) {
last_one = i; last_one = i;
i++; i++;
if (i >= (int)tiles.size()) { if (i >= static_cast<int>(tiles.size())) {
break; break;
} }
} }
@@ -333,7 +333,7 @@ void CollisionMap::buildHorizontalLines(const std::vector<int>& tiles, std::vect
lines.push_back(line); lines.push_back(line);
// Salta separadores // Salta separadores
if (i < (int)tiles.size() && tiles[i] == -1) { if (i < static_cast<int>(tiles.size()) && tiles[i] == -1) {
i++; i++;
} }
} }
@@ -354,7 +354,7 @@ void CollisionMap::setTopSurfaces() {
} }
// Calcula las superficies laterales izquierdas // Calcula las superficies laterales izquierdas
void CollisionMap::setLeftSurfaces() { void CollisionMap::setLeftSurfaces() { // NOLINT(readability-make-member-function-const)
std::vector<int> tile; std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tienen a su izquierda un tile de tipo muro // Busca todos los tiles de tipo muro que no tienen a su izquierda un tile de tipo muro
@@ -394,7 +394,7 @@ void CollisionMap::setLeftSurfaces() {
} }
// Calcula las superficies laterales derechas // Calcula las superficies laterales derechas
void CollisionMap::setRightSurfaces() { void CollisionMap::setRightSurfaces() { // NOLINT(readability-make-member-function-const)
std::vector<int> tile; std::vector<int> tile;
// Busca todos los tiles de tipo muro que no tienen a su derecha un tile de tipo muro // Busca todos los tiles de tipo muro que no tienen a su derecha un tile de tipo muro
@@ -434,7 +434,7 @@ void CollisionMap::setRightSurfaces() {
} }
// Encuentra todas las rampas que suben hacia la izquierda // Encuentra todas las rampas que suben hacia la izquierda
void CollisionMap::setLeftSlopes() { void CollisionMap::setLeftSlopes() { // NOLINT(readability-make-member-function-const)
// Recorre la habitación entera por filas buscando tiles de tipo t_slope_l // Recorre la habitación entera por filas buscando tiles de tipo t_slope_l
std::vector<int> found; std::vector<int> found;
for (int i = 0; i < (int)tile_map_.size(); ++i) { for (int i = 0; i < (int)tile_map_.size(); ++i) {
@@ -469,7 +469,7 @@ void CollisionMap::setLeftSlopes() {
} }
// Encuentra todas las rampas que suben hacia la derecha // Encuentra todas las rampas que suben hacia la derecha
void CollisionMap::setRightSlopes() { void CollisionMap::setRightSlopes() { // NOLINT(readability-make-member-function-const)
// Recorre la habitación entera por filas buscando tiles de tipo t_slope_r // Recorre la habitación entera por filas buscando tiles de tipo t_slope_r
std::vector<int> found; std::vector<int> found;
for (int i = 0; i < (int)tile_map_.size(); ++i) { for (int i = 0; i < (int)tile_map_.size(); ++i) {

View File

@@ -6,7 +6,7 @@
#include "utils/utils.hpp" // Para checkCollision #include "utils/utils.hpp" // Para checkCollision
// Añade un enemigo a la colección // Añade un enemigo a la colección
void EnemyManager::addEnemy(std::shared_ptr<Enemy> enemy) { void EnemyManager::addEnemy(std::shared_ptr<Enemy> enemy) { // NOLINT(readability-identifier-naming)
enemies_.push_back(std::move(enemy)); enemies_.push_back(std::move(enemy));
} }
@@ -16,7 +16,7 @@ void EnemyManager::clear() {
} }
// Elimina el último enemigo de la colección // Elimina el último enemigo de la colección
void EnemyManager::removeLastEnemy() { void EnemyManager::removeLastEnemy() { // NOLINT(readability-convert-member-functions-to-static)
if (!enemies_.empty()) { if (!enemies_.empty()) {
enemies_.pop_back(); enemies_.pop_back();
} }

View File

@@ -14,7 +14,7 @@ ItemManager::ItemManager(std::string room_name, std::shared_ptr<Scoreboard::Data
} }
// Añade un item a la colección // Añade un item a la colección
void ItemManager::addItem(std::shared_ptr<Item> item) { void ItemManager::addItem(std::shared_ptr<Item> item) { // NOLINT(readability-identifier-naming)
items_.push_back(std::move(item)); items_.push_back(std::move(item));
} }
@@ -45,7 +45,7 @@ void ItemManager::setPaused(bool paused) {
} }
// Comprueba si hay colisión con algún item // Comprueba si hay colisión con algún item
auto ItemManager::checkCollision(SDL_FRect& rect) -> bool { auto ItemManager::checkCollision(SDL_FRect& rect) -> bool { // NOLINT(readability-convert-member-functions-to-static)
for (int i = 0; i < static_cast<int>(items_.size()); ++i) { for (int i = 0; i < static_cast<int>(items_.size()); ++i) {
if (::checkCollision(rect, items_.at(i)->getCollider())) { if (::checkCollision(rect, items_.at(i)->getCollider())) {
// Registra el item como recogido // Registra el item como recogido

View File

@@ -32,7 +32,7 @@ auto ItemTracker::hasBeenPicked(const std::string& name, SDL_FPoint pos) -> bool
} }
// Añade el objeto a la lista de objetos cogidos // Añade el objeto a la lista de objetos cogidos
void ItemTracker::addItem(const std::string& name, SDL_FPoint pos) { void ItemTracker::addItem(const std::string& name, SDL_FPoint pos) { // NOLINT(readability-convert-member-functions-to-static)
// Comprueba si el objeto no ha sido recogido con anterioridad // Comprueba si el objeto no ha sido recogido con anterioridad
if (!hasBeenPicked(name, pos)) { if (!hasBeenPicked(name, pos)) {
// Primero busca si ya hay una entrada con ese nombre // Primero busca si ya hay una entrada con ese nombre
@@ -47,7 +47,7 @@ void ItemTracker::addItem(const std::string& name, SDL_FPoint pos) {
} }
// Busca una entrada en la lista por nombre // Busca una entrada en la lista por nombre
auto ItemTracker::findByName(const std::string& name) -> int { auto ItemTracker::findByName(const std::string& name) -> int { // NOLINT(readability-convert-member-functions-to-static)
int i = 0; int i = 0;
for (const auto& item : items_) { for (const auto& item : items_) {
@@ -61,7 +61,7 @@ auto ItemTracker::findByName(const std::string& name) -> int {
} }
// Busca una entrada en la lista por posición // Busca una entrada en la lista por posición
auto ItemTracker::findByPos(int index, SDL_FPoint pos) -> int { auto ItemTracker::findByPos(int index, SDL_FPoint pos) -> int { // NOLINT(readability-convert-member-functions-to-static)
int i = 0; int i = 0;
for (const auto& item : items_[index].pos) { for (const auto& item : items_[index].pos) {

View File

@@ -81,7 +81,7 @@ void Room::initializeRoom(const Data& room) {
} }
// Abre la jail para poder entrar // Abre la jail para poder entrar
void Room::openTheJail() { void Room::openTheJail() { // NOLINT(readability-convert-member-functions-to-static)
if (data_->jail_is_open && name_ == "THE JAIL") { if (data_->jail_is_open && name_ == "THE JAIL") {
// Elimina el último enemigo (Bry debe ser el último enemigo definido en el fichero) // Elimina el último enemigo (Bry debe ser el último enemigo definido en el fichero)
if (!enemy_manager_->isEmpty()) { if (!enemy_manager_->isEmpty()) {
@@ -123,7 +123,7 @@ void Room::redrawMap() {
#endif #endif
// Actualiza las variables y objetos de la habitación // Actualiza las variables y objetos de la habitación
void Room::update(float delta_time) { void Room::update(float delta_time) { // NOLINT(readability-make-member-function-const)
if (is_paused_) { if (is_paused_) {
// Si está en modo pausa no se actualiza nada // Si está en modo pausa no se actualiza nada
return; return;
@@ -147,7 +147,7 @@ void Room::setPaused(bool value) {
} }
// Devuelve la cadena del fichero de la habitación contigua segun el borde // Devuelve la cadena del fichero de la habitación contigua segun el borde
auto Room::getRoom(Border border) -> std::string { auto Room::getRoom(Border border) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
switch (border) { switch (border) {
case Border::TOP: case Border::TOP:
return upper_room_; return upper_room_;
@@ -163,14 +163,14 @@ auto Room::getRoom(Border border) -> std::string {
} }
// Devuelve el tipo de tile que hay en ese pixel // Devuelve el tipo de tile que hay en ese pixel
auto Room::getTile(SDL_FPoint point) -> Tile { auto Room::getTile(SDL_FPoint point) -> Tile { // NOLINT(readability-convert-member-functions-to-static)
// Delega a CollisionMap y convierte el resultado // Delega a CollisionMap y convierte el resultado
const auto COLLISION_TILE = collision_map_->getTile(point); const auto COLLISION_TILE = collision_map_->getTile(point);
return static_cast<Tile>(COLLISION_TILE); return static_cast<Tile>(COLLISION_TILE);
} }
// Devuelve el tipo de tile en un índice del tilemap // Devuelve el tipo de tile en un índice del tilemap
auto Room::getTile(int index) -> Tile { auto Room::getTile(int index) -> Tile { // NOLINT(readability-convert-member-functions-to-static)
// Delega a CollisionMap y convierte el resultado // Delega a CollisionMap y convierte el resultado
const auto COLLISION_TILE = collision_map_->getTile(index); const auto COLLISION_TILE = collision_map_->getTile(index);
return static_cast<Tile>(COLLISION_TILE); return static_cast<Tile>(COLLISION_TILE);
@@ -256,6 +256,6 @@ auto Room::getSlopeAtPoint(const SDL_FPoint& p) const -> const LineDiagonal* {
} }
// Carga una habitación desde un archivo YAML (delegado a RoomLoader) // Carga una habitación desde un archivo YAML (delegado a RoomLoader)
auto Room::loadYAML(const std::string& file_path, bool verbose) -> Data { auto Room::loadYAML(const std::string& file_path, bool verbose) -> Data { // NOLINT(readability-convert-member-functions-to-static)
return RoomLoader::loadYAML(file_path, verbose); return RoomLoader::loadYAML(file_path, verbose);
} }

View File

@@ -10,7 +10,7 @@
#include "game/entities/item.hpp" // Para ItemData #include "game/entities/item.hpp" // Para ItemData
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data #include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
#include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical #include "utils/utils.hpp" // Para LineHorizontal, LineDiagonal, LineVertical
class SurfaceSprite; // lines 12-12 class Sprite; // lines 12-12
class Surface; // lines 13-13 class Surface; // lines 13-13
class EnemyManager; class EnemyManager;
class ItemManager; class ItemManager;
@@ -58,7 +58,7 @@ class Room {
// Constructor y destructor // Constructor y destructor
Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data); Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data);
~Room(); // Definido en .cpp para poder usar unique_ptr con forward declarations ~Room(); // NOLINT(modernize-use-equals-default, performance-trivially-destructible) -- defined in .cpp for unique_ptr with forward declarations
// --- Funciones --- // --- Funciones ---
[[nodiscard]] auto getName() const -> const std::string& { return name_; } // Devuelve el nombre de la habitación [[nodiscard]] auto getName() const -> const std::string& { return name_; } // Devuelve el nombre de la habitación

View File

@@ -10,7 +10,7 @@
#include "utils/utils.hpp" // Para stringToColor #include "utils/utils.hpp" // Para stringToColor
// Convierte room connection de YAML a formato interno // Convierte room connection de YAML a formato interno
auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string { auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string { // NOLINT(readability-convert-member-functions-to-static)
if (value == "null" || value.empty()) { if (value == "null" || value.empty()) {
return "0"; return "0";
} }
@@ -22,7 +22,7 @@ auto RoomLoader::convertRoomConnection(const std::string& value) -> std::string
} }
// Convierte string de autoSurface a int // Convierte string de autoSurface a int
auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int { auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int { // NOLINT(readability-convert-member-functions-to-static)
if (node.is_integer()) { if (node.is_integer()) {
return node.get_value<int>(); return node.get_value<int>();
} }
@@ -39,7 +39,7 @@ auto RoomLoader::convertAutoSurface(const fkyaml::node& node) -> int {
} }
// Convierte un tilemap 2D a vector 1D flat // Convierte un tilemap 2D a vector 1D flat
auto RoomLoader::flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int> { auto RoomLoader::flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int> { // NOLINT(readability-convert-member-functions-to-static, readability-named-parameter)
std::vector<int> tilemap_flat; std::vector<int> tilemap_flat;
tilemap_flat.reserve(512); // 16 rows × 32 cols tilemap_flat.reserve(512); // 16 rows × 32 cols
@@ -53,7 +53,7 @@ auto RoomLoader::flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d)
} }
// Parsea la configuración general de la habitación // Parsea la configuración general de la habitación
void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name) { void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name) { // NOLINT(readability-convert-member-functions-to-static)
if (!yaml.contains("room")) { if (!yaml.contains("room")) {
return; return;
} }
@@ -120,7 +120,7 @@ void RoomLoader::parseRoomConnections(const fkyaml::node& conn_node, Room::Data&
} }
// Parsea el tilemap de la habitación // Parsea el tilemap de la habitación
void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose) { void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const std::string& file_name, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
if (!yaml.contains("tilemap")) { if (!yaml.contains("tilemap")) {
std::cerr << "Warning: No tilemap found in " << file_name << '\n'; std::cerr << "Warning: No tilemap found in " << file_name << '\n';
return; return;
@@ -152,7 +152,7 @@ void RoomLoader::parseTilemap(const fkyaml::node& yaml, Room::Data& room, const
} }
// Parsea los límites de movimiento de un enemigo // Parsea los límites de movimiento de un enemigo
void RoomLoader::parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy) { void RoomLoader::parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Data& enemy) { // NOLINT(readability-convert-member-functions-to-static)
// Nuevo formato: position1 y position2 // Nuevo formato: position1 y position2
if (bounds_node.contains("position1")) { if (bounds_node.contains("position1")) {
const auto& pos1 = bounds_node["position1"]; const auto& pos1 = bounds_node["position1"];
@@ -189,7 +189,7 @@ void RoomLoader::parseEnemyBoundaries(const fkyaml::node& bounds_node, Enemy::Da
} }
// Parsea los datos de un enemigo individual // Parsea los datos de un enemigo individual
auto RoomLoader::parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data { auto RoomLoader::parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data { // NOLINT(readability-convert-member-functions-to-static)
Enemy::Data enemy; Enemy::Data enemy;
// Animation path // Animation path
@@ -246,7 +246,7 @@ auto RoomLoader::parseEnemyData(const fkyaml::node& enemy_node) -> Enemy::Data {
} }
// Parsea la lista de enemigos de la habitación // Parsea la lista de enemigos de la habitación
void RoomLoader::parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose) { void RoomLoader::parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
if (!yaml.contains("enemies") || yaml["enemies"].is_null()) { if (!yaml.contains("enemies") || yaml["enemies"].is_null()) {
return; return;
} }
@@ -263,7 +263,7 @@ void RoomLoader::parseEnemies(const fkyaml::node& yaml, Room::Data& room, bool v
} }
// Parsea los datos de un item individual // Parsea los datos de un item individual
auto RoomLoader::parseItemData(const fkyaml::node& item_node, const Room::Data& room) -> Item::Data { auto RoomLoader::parseItemData(const fkyaml::node& item_node, const Room::Data& room) -> Item::Data { // NOLINT(readability-convert-member-functions-to-static)
Item::Data item; Item::Data item;
// Tileset file // Tileset file
@@ -300,7 +300,7 @@ auto RoomLoader::parseItemData(const fkyaml::node& item_node, const Room::Data&
} }
// Parsea la lista de items de la habitación // Parsea la lista de items de la habitación
void RoomLoader::parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose) { void RoomLoader::parseItems(const fkyaml::node& yaml, Room::Data& room, bool verbose) { // NOLINT(readability-convert-member-functions-to-static)
if (!yaml.contains("items") || yaml["items"].is_null()) { if (!yaml.contains("items") || yaml["items"].is_null()) {
return; return;
} }
@@ -317,7 +317,7 @@ void RoomLoader::parseItems(const fkyaml::node& yaml, Room::Data& room, bool ver
} }
// Carga un archivo de room en formato YAML // Carga un archivo de room en formato YAML
auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data { auto RoomLoader::loadYAML(const std::string& file_path, bool verbose) -> Room::Data { // NOLINT(readability-convert-member-functions-to-static)
Room::Data room; Room::Data room;
// Extract filename for logging // Extract filename for logging

View File

@@ -67,7 +67,7 @@ class RoomLoader {
* @param tilemap_2d Array 2D de tiles (16 rows × 32 cols) * @param tilemap_2d Array 2D de tiles (16 rows × 32 cols)
* @return Vector 1D flat con 512 elementos * @return Vector 1D flat con 512 elementos
*/ */
static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>; static auto flattenTilemap(const std::vector<std::vector<int>>& tilemap_2d) -> std::vector<int>; // NOLINT(readability-avoid-const-params-in-decls)
/** /**
* @brief Parsea la configuración general de la habitación * @brief Parsea la configuración general de la habitación

View File

@@ -3,17 +3,17 @@
#include <algorithm> // Para std::ranges::any_of #include <algorithm> // Para std::ranges::any_of
// Comprueba si la habitación ya ha sido visitada // Comprueba si la habitación ya ha sido visitada
auto RoomTracker::hasBeenVisited(const std::string& name) -> bool { auto RoomTracker::hasBeenVisited(const std::string& name) -> bool { // NOLINT(readability-convert-member-functions-to-static)
return std::ranges::any_of(rooms_, [&name](const auto& l) { return l == name; }); return std::ranges::any_of(rooms_, [&name](const auto& l) -> bool { return l == name; });
} }
// Añade la habitación a la lista // Añade la habitación a la lista
auto RoomTracker::addRoom(const std::string& name) -> bool { auto RoomTracker::addRoom(const std::string& name) -> bool { // NOLINT(readability-convert-member-functions-to-static)
// Comprueba si la habitación ya ha sido visitada // Comprueba si la habitación ya ha sido visitada
if (!hasBeenVisited(name)) { if (!hasBeenVisited(name)) {
// En caso contrario añádela a la lista // En caso contrario añádela a la lista
rooms_.push_back(name); rooms_.push_back(name);
return true; return true; // NOLINT(readability-simplify-boolean-expr)
} }
return false; return false;

View File

@@ -4,15 +4,15 @@
#include <utility> #include <utility>
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/text.hpp" // Para Text #include "core/rendering/text.hpp" // Para Text
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame #include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
#include "utils/defines.hpp" // Para BLOCK #include "utils/defines.hpp" // Para BLOCK
#include "utils/utils.hpp" // Para stringToColor #include "utils/utils.hpp" // Para stringToColor
// Constructor // Constructor
Scoreboard::Scoreboard(std::shared_ptr<Data> data) Scoreboard::Scoreboard(std::shared_ptr<Data> data)
@@ -23,7 +23,7 @@ Scoreboard::Scoreboard(std::shared_ptr<Data> data)
// Reserva memoria para los objetos // Reserva memoria para los objetos
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.yaml" : "player.yaml"); const auto& player_animation_data = Resource::Cache::get()->getAnimationData(Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.yaml" : "player.yaml");
player_sprite_ = std::make_shared<SurfaceAnimatedSprite>(player_animation_data); player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
player_sprite_->setCurrentAnimation("walk_menu"); player_sprite_->setCurrentAnimation("walk_menu");
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT); surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
@@ -65,7 +65,7 @@ void Scoreboard::update(float delta_time) {
} }
// Obtiene el tiempo transcurrido de partida // Obtiene el tiempo transcurrido de partida
auto Scoreboard::getTime() -> Scoreboard::ClockData { auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-convert-member-functions-to-static)
const Uint32 TIME_ELAPSED = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_; const Uint32 TIME_ELAPSED = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
ClockData time; ClockData time;
@@ -149,7 +149,7 @@ void Scoreboard::fillTexture() {
// Muestra si suena la música // Muestra si suena la música
if (data_->music) { if (data_->music) {
const Uint8 C = data_->color; const Uint8 C = data_->color;
SDL_FRect clip = {0, 8, 8, 8}; SDL_FRect clip = {.x = 0, .y = 8, .w = 8, .h = 8};
item_surface_->renderWithColorReplace(20 * Tile::SIZE, LINE2, 1, C, &clip); item_surface_->renderWithColorReplace(20 * Tile::SIZE, LINE2, 1, C, &clip);
} }
@@ -157,13 +157,13 @@ void Scoreboard::fillTexture() {
auto text = Resource::Cache::get()->getText("smb2"); auto text = Resource::Cache::get()->getText("smb2");
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10); const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10); const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
text->writeColored(Tile::SIZE, LINE1, Locale::get()->get("scoreboard.items"), data_->color); text->writeColored(Tile::SIZE, LINE1, Locale::get()->get("scoreboard.items"), data_->color); // NOLINT(readability-static-accessed-through-instance)
text->writeColored(17 * Tile::SIZE, LINE1, ITEMS_TEXT, items_color_); text->writeColored(17 * Tile::SIZE, LINE1, ITEMS_TEXT, items_color_);
text->writeColored(20 * Tile::SIZE, LINE1, Locale::get()->get("scoreboard.time"), data_->color); text->writeColored(20 * Tile::SIZE, LINE1, Locale::get()->get("scoreboard.time"), data_->color); // NOLINT(readability-static-accessed-through-instance)
text->writeColored(26 * Tile::SIZE, LINE1, TIME_TEXT, stringToColor("white")); text->writeColored(26 * Tile::SIZE, LINE1, TIME_TEXT, stringToColor("white"));
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10); const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
text->writeColored(22 * Tile::SIZE, LINE2, Locale::get()->get("scoreboard.rooms"), stringToColor("white")); text->writeColored(22 * Tile::SIZE, LINE2, Locale::get()->get("scoreboard.rooms"), stringToColor("white")); // NOLINT(readability-static-accessed-through-instance)
text->writeColored(28 * Tile::SIZE, LINE2, ROOMS_TEXT, stringToColor("white")); text->writeColored(28 * Tile::SIZE, LINE2, ROOMS_TEXT, stringToColor("white"));
// Deja el renderizador como estaba // Deja el renderizador como estaba

View File

@@ -5,9 +5,9 @@
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string, basic_string #include <string> // Para string, basic_string
#include <utility> #include <utility>
#include <vector> // Para vector #include <vector> // Para vector
class SurfaceAnimatedSprite; // lines 10-10 class AnimatedSprite; // lines 10-10
class Surface; // lines 11-11 class Surface; // lines 11-11
class Scoreboard { class Scoreboard {
public: public:
@@ -50,10 +50,10 @@ class Scoreboard {
void fillTexture(); // Dibuja los elementos del marcador en la surface void fillTexture(); // Dibuja los elementos del marcador en la surface
// Objetos y punteros // Objetos y punteros
std::shared_ptr<SurfaceAnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador std::shared_ptr<AnimatedSprite> player_sprite_; // Sprite para mostrar las vidas en el marcador
std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador std::shared_ptr<Surface> item_surface_; // Surface con los graficos para los elementos del marcador
std::shared_ptr<Data> data_; // Contiene las variables a mostrar en el marcador std::shared_ptr<Data> data_; // Contiene las variables a mostrar en el marcador
std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador std::shared_ptr<Surface> surface_; // Surface donde dibujar el marcador
// Variables de estado // Variables de estado
std::vector<Uint8> color_; // Vector con los colores del objeto std::vector<Uint8> color_; // Vector con los colores del objeto

View File

@@ -40,7 +40,7 @@ void Stats::init()
} }
// Añade una muerte a las estadisticas // Añade una muerte a las estadisticas
void Stats::addDeath(const std::string& name) { void Stats::addDeath(const std::string& name) { // NOLINT(readability-convert-member-functions-to-static)
// Primero busca si ya hay una entrada con ese nombre // Primero busca si ya hay una entrada con ese nombre
const int INDEX = findByName(name, buffer_list_); const int INDEX = findByName(name, buffer_list_);
if (INDEX != -1) { if (INDEX != -1) {
@@ -58,7 +58,7 @@ void Stats::addDeath(const std::string& name) {
} }
// Añade una visita a las estadisticas // Añade una visita a las estadisticas
void Stats::addVisit(const std::string& name) { void Stats::addVisit(const std::string& name) { // NOLINT(readability-convert-member-functions-to-static)
// Primero busca si ya hay una entrada con ese nombre // Primero busca si ya hay una entrada con ese nombre
const int INDEX = findByName(name, buffer_list_); const int INDEX = findByName(name, buffer_list_);
if (INDEX != -1) { if (INDEX != -1) {
@@ -76,7 +76,7 @@ void Stats::addVisit(const std::string& name) {
} }
// Busca una entrada en la lista por nombre // Busca una entrada en la lista por nombre
auto Stats::findByName(const std::string& name, const std::vector<RoomData>& list) -> int { auto Stats::findByName(const std::string& name, const std::vector<RoomData>& list) -> int { // NOLINT(readability-convert-member-functions-to-static)
int i = 0; int i = 0;
for (const auto& l : list) { for (const auto& l : list) {
@@ -90,7 +90,7 @@ auto Stats::findByName(const std::string& name, const std::vector<RoomData>& lis
} }
// Carga las estadisticas desde un fichero // Carga las estadisticas desde un fichero
auto Stats::loadFromFile(const std::string& file_path, std::vector<RoomData>& list) -> bool { auto Stats::loadFromFile(const std::string& file_path, std::vector<RoomData>& list) -> bool { // NOLINT(readability-convert-member-functions-to-static)
list.clear(); list.clear();
// Indicador de éxito en la carga // Indicador de éxito en la carga
@@ -109,7 +109,7 @@ auto Stats::loadFromFile(const std::string& file_path, std::vector<RoomData>& li
line.pop_back(); line.pop_back();
} }
// Comprueba que la linea no sea un comentario // Comprueba que la linea no sea un comentario
if (line.substr(0, 1) != "#") { if (!line.starts_with("#")) {
RoomData stat; RoomData stat;
std::stringstream ss(line); std::stringstream ss(line);
std::string tmp; std::string tmp;
@@ -159,7 +159,7 @@ void Stats::saveToFile(const std::string& file_path, const std::vector<RoomData>
} }
// Calcula cual es la habitación con más muertes // Calcula cual es la habitación con más muertes
void Stats::checkWorstNightmare() { void Stats::checkWorstNightmare() { // NOLINT(readability-convert-member-functions-to-static)
int deaths = 0; int deaths = 0;
for (const auto& item : list_) { for (const auto& item : list_) {
if (item.died > deaths) { if (item.died > deaths) {
@@ -171,7 +171,7 @@ void Stats::checkWorstNightmare() {
// Añade una entrada al diccionario // Añade una entrada al diccionario
void Stats::addDictionary(const std::string& number, const std::string& name) { void Stats::addDictionary(const std::string& number, const std::string& name) {
dictionary_.push_back({number, name}); dictionary_.push_back({.number = number, .name = name});
} }
// Vuelca los datos del buffer en la lista de estadisticas // Vuelca los datos del buffer en la lista de estadisticas

View File

@@ -1,8 +1,8 @@
#include "tilemap_renderer.hpp" #include "tilemap_renderer.hpp"
#include "core/rendering/screen.hpp" #include "core/rendering/screen.hpp"
#include "core/rendering/sprite/sprite.hpp"
#include "core/rendering/surface.hpp" #include "core/rendering/surface.hpp"
#include "core/rendering/surface_sprite.hpp"
#ifdef _DEBUG #ifdef _DEBUG
#include "core/system/debug.hpp" #include "core/system/debug.hpp"
#endif #endif
@@ -42,7 +42,7 @@ void TilemapRenderer::update(float delta_time) {
// Renderiza el mapa completo en pantalla // Renderiza el mapa completo en pantalla
void TilemapRenderer::render() { void TilemapRenderer::render() {
// Dibuja la textura con el mapa en pantalla // Dibuja la textura con el mapa en pantalla
SDL_FRect dest = {0, 0, PlayArea::WIDTH, PlayArea::HEIGHT}; SDL_FRect dest = {.x = 0, .y = 0, .w = PlayArea::WIDTH, .h = PlayArea::HEIGHT};
map_surface_->render(nullptr, &dest); map_surface_->render(nullptr, &dest);
// Dibuja los tiles animados // Dibuja los tiles animados
@@ -103,7 +103,7 @@ void TilemapRenderer::redrawMap(const CollisionMap* collision_map) {
#endif #endif
// Pinta el mapa estático y debug lines // Pinta el mapa estático y debug lines
void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) { void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) { // NOLINT(readability-convert-member-functions-to-static)
const Uint8 COLOR = stringToColor(bg_color_); const Uint8 COLOR = stringToColor(bg_color_);
auto previous_renderer = Screen::get()->getRendererSurface(); auto previous_renderer = Screen::get()->getRendererSurface();
Screen::get()->setRendererSurface(map_surface_); Screen::get()->setRendererSurface(map_surface_);
@@ -111,7 +111,7 @@ void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) {
// Los tileSetFiles son de 20x20 tiles. El primer tile es el 0. Cuentan hacia la derecha y hacia abajo // Los tileSetFiles son de 20x20 tiles. El primer tile es el 0. Cuentan hacia la derecha y hacia abajo
SDL_FRect clip = {0, 0, TILE_SIZE, TILE_SIZE}; SDL_FRect clip = {.x = 0, .y = 0, .w = TILE_SIZE, .h = TILE_SIZE};
for (int y = 0; y < MAP_HEIGHT; ++y) { for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x) { for (int x = 0; x < MAP_WIDTH; ++x) {
// Tiled pone los tiles vacios del mapa como cero y empieza a contar de 1 a n. // Tiled pone los tiles vacios del mapa como cero y empieza a contar de 1 a n.
@@ -145,7 +145,7 @@ void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) {
} }
// Localiza todos los tiles animados // Localiza todos los tiles animados
void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) { void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) { // NOLINT(readability-convert-member-functions-to-static)
// Recorre la habitación entera por filas buscando tiles de tipo t_animated // Recorre la habitación entera por filas buscando tiles de tipo t_animated
for (int i = 0; i < (int)tile_map_.size(); ++i) { for (int i = 0; i < (int)tile_map_.size(); ++i) {
const auto TILE_TYPE = collision_map->getTile(i); const auto TILE_TYPE = collision_map->getTile(i);
@@ -159,7 +159,7 @@ void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) {
const int YC = (tile_map_[i] / tile_set_width_) * TILE_SIZE; const int YC = (tile_map_[i] / tile_set_width_) * TILE_SIZE;
AnimatedTile at; AnimatedTile at;
at.sprite = std::make_shared<SurfaceSprite>(tileset_surface_, X, Y, 8, 8); at.sprite = std::make_shared<Sprite>(tileset_surface_, X, Y, 8, 8);
at.sprite->setClip(XC, YC, 8, 8); at.sprite->setClip(XC, YC, 8, 8);
at.x_orig = XC; at.x_orig = XC;
animated_tiles_.push_back(at); animated_tiles_.push_back(at);
@@ -168,7 +168,7 @@ void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) {
} }
// Actualiza tiles animados // Actualiza tiles animados
void TilemapRenderer::updateAnimatedTiles() { void TilemapRenderer::updateAnimatedTiles() { // NOLINT(readability-make-member-function-const)
const int NUM_FRAMES = 4; const int NUM_FRAMES = 4;
// Calcular frame actual basado en tiempo // Calcular frame actual basado en tiempo

View File

@@ -9,7 +9,7 @@
#include "utils/defines.hpp" #include "utils/defines.hpp"
class Surface; class Surface;
class SurfaceSprite; class Sprite;
class CollisionMap; class CollisionMap;
/** /**
@@ -85,8 +85,8 @@ class TilemapRenderer {
private: private:
// Estructura para tiles animados (conveyor belts) // Estructura para tiles animados (conveyor belts)
struct AnimatedTile { struct AnimatedTile {
std::shared_ptr<SurfaceSprite> sprite{nullptr}; // SurfaceSprite para dibujar el tile std::shared_ptr<Sprite> sprite{nullptr}; // SurfaceSprite para dibujar el tile
int x_orig{0}; // Posición X del primer tile de la animación en tilesheet int x_orig{0}; // Posición X del primer tile de la animación en tilesheet
}; };
// === Constantes === // === Constantes ===

View File

@@ -308,6 +308,17 @@ namespace Options {
} }
} }
// Helper: carga el campo palette con validación extra
void loadPaletteFromYaml(const fkyaml::node& vid) {
if (!vid.contains("palette")) { return; }
try {
auto palette_str = vid["palette"].get_value<std::string>();
video.palette = isValidPalette(palette_str) ? palette_str : Defaults::Video::PALETTE_NAME;
} catch (...) {
video.palette = Defaults::Video::PALETTE_NAME;
}
}
// Carga los campos básicos de configuración de video // Carga los campos básicos de configuración de video
void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) { void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) {
// fullscreen (antes era "mode") // fullscreen (antes era "mode")
@@ -377,18 +388,7 @@ namespace Options {
} }
} }
if (vid.contains("palette")) { loadPaletteFromYaml(vid);
try {
auto palette_str = vid["palette"].get_value<std::string>();
if (isValidPalette(palette_str)) {
video.palette = palette_str;
} else {
video.palette = Defaults::Video::PALETTE_NAME;
}
} catch (...) {
video.palette = Defaults::Video::PALETTE_NAME;
}
}
} }
// Carga configuración de video desde YAML // Carga configuración de video desde YAML
@@ -735,6 +735,7 @@ namespace Options {
parseFloatField(p, "gamma", preset.gamma); parseFloatField(p, "gamma", preset.gamma);
parseFloatField(p, "curvature", preset.curvature); parseFloatField(p, "curvature", preset.curvature);
parseFloatField(p, "bleeding", preset.bleeding); parseFloatField(p, "bleeding", preset.bleeding);
parseFloatField(p, "flicker", preset.flicker);
// Nota: 'supersampling' era un campo por-preset (eliminado). Si existe // Nota: 'supersampling' era un campo por-preset (eliminado). Si existe
// en el fichero del usuario se ignora silenciosamente (compatible). // en el fichero del usuario se ignora silenciosamente (compatible).
postfx_presets.push_back(preset); postfx_presets.push_back(preset);
@@ -744,7 +745,9 @@ namespace Options {
// Preservar el índice cargado desde config.yaml; clampar al rango válido. // Preservar el índice cargado desde config.yaml; clampar al rango válido.
if (!postfx_presets.empty()) { if (!postfx_presets.empty()) {
current_postfx_preset = std::clamp( current_postfx_preset = std::clamp(
current_postfx_preset, 0, static_cast<int>(postfx_presets.size()) - 1); current_postfx_preset,
0,
static_cast<int>(postfx_presets.size()) - 1);
} else { } else {
current_postfx_preset = 0; current_postfx_preset = 0;
} }
@@ -786,6 +789,7 @@ namespace Options {
file << "# gamma: gamma correction input 2.4 / output 2.2\n"; file << "# gamma: gamma correction input 2.4 / output 2.2\n";
file << "# curvature: CRT barrel distortion\n"; file << "# curvature: CRT barrel distortion\n";
file << "# bleeding: NTSC horizontal colour bleeding\n"; file << "# bleeding: NTSC horizontal colour bleeding\n";
file << "# flicker: phosphor CRT flicker ~50 Hz (0.0 = off, 1.0 = max)\n";
file << "# Note: supersampling is a global toggle in config.yaml, not per-preset.\n"; file << "# Note: supersampling is a global toggle in config.yaml, not per-preset.\n";
file << "\n"; file << "\n";
file << "presets:\n"; file << "presets:\n";
@@ -797,6 +801,7 @@ namespace Options {
file << " gamma: 0.8\n"; file << " gamma: 0.8\n";
file << " curvature: 0.0\n"; file << " curvature: 0.0\n";
file << " bleeding: 0.0\n"; file << " bleeding: 0.0\n";
file << " flicker: 0.0\n";
file << " - name: \"NTSC\"\n"; file << " - name: \"NTSC\"\n";
file << " vignette: 0.4\n"; file << " vignette: 0.4\n";
file << " scanlines: 0.5\n"; file << " scanlines: 0.5\n";
@@ -805,6 +810,7 @@ namespace Options {
file << " gamma: 0.5\n"; file << " gamma: 0.5\n";
file << " curvature: 0.0\n"; file << " curvature: 0.0\n";
file << " bleeding: 0.6\n"; file << " bleeding: 0.6\n";
file << " flicker: 0.0\n";
file << " - name: \"CURVED\"\n"; file << " - name: \"CURVED\"\n";
file << " vignette: 0.5\n"; file << " vignette: 0.5\n";
file << " scanlines: 0.6\n"; file << " scanlines: 0.6\n";
@@ -813,6 +819,7 @@ namespace Options {
file << " gamma: 0.7\n"; file << " gamma: 0.7\n";
file << " curvature: 0.8\n"; file << " curvature: 0.8\n";
file << " bleeding: 0.0\n"; file << " bleeding: 0.0\n";
file << " flicker: 0.0\n";
file << " - name: \"SCANLINES\"\n"; file << " - name: \"SCANLINES\"\n";
file << " vignette: 0.0\n"; file << " vignette: 0.0\n";
file << " scanlines: 0.8\n"; file << " scanlines: 0.8\n";
@@ -821,6 +828,7 @@ namespace Options {
file << " gamma: 0.0\n"; file << " gamma: 0.0\n";
file << " curvature: 0.0\n"; file << " curvature: 0.0\n";
file << " bleeding: 0.0\n"; file << " bleeding: 0.0\n";
file << " flicker: 0.0\n";
file << " - name: \"SUBTLE\"\n"; file << " - name: \"SUBTLE\"\n";
file << " vignette: 0.3\n"; file << " vignette: 0.3\n";
file << " scanlines: 0.4\n"; file << " scanlines: 0.4\n";
@@ -829,6 +837,16 @@ namespace Options {
file << " gamma: 0.3\n"; file << " gamma: 0.3\n";
file << " curvature: 0.0\n"; file << " curvature: 0.0\n";
file << " bleeding: 0.0\n"; file << " bleeding: 0.0\n";
file << " flicker: 0.0\n";
file << " - name: \"CRT LIVE\"\n";
file << " vignette: 0.5\n";
file << " scanlines: 0.6\n";
file << " chroma: 0.3\n";
file << " mask: 0.3\n";
file << " gamma: 0.4\n";
file << " curvature: 0.3\n";
file << " bleeding: 0.4\n";
file << " flicker: 0.8\n";
file.close(); file.close();
@@ -838,11 +856,12 @@ namespace Options {
// Cargar los presets recién creados // Cargar los presets recién creados
postfx_presets.clear(); postfx_presets.clear();
postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.15F, 0.6F, 0.8F, 0.0F, 0.0F}); postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.3F, 0.6F, 0.8F, 0.0F, 0.0F, 0.0F});
postfx_presets.push_back({"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F}); postfx_presets.push_back({"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F, 0.0F});
postfx_presets.push_back({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F, 0.0F}); postfx_presets.push_back({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F, 0.0F, 0.0F});
postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F}); postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F});
postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F}); postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 0.0F});
postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F});
current_postfx_preset = 0; current_postfx_preset = 0;
return true; return true;

View File

@@ -117,14 +117,15 @@ namespace Options {
// Estructura para un preset de PostFX // Estructura para un preset de PostFX
struct PostFXPreset { struct PostFXPreset {
std::string name; // Nombre del preset std::string name; // Nombre del preset
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima) float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas) float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
float chroma{0.15F}; // Intensidad de la aberración cromática (0.0 = ninguna, 1.0 = máxima) float chroma{0.15F}; // Intensidad de la aberración cromática (0.0 = ninguna, 1.0 = máxima)
float mask{0.0F}; // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima) float mask{0.0F}; // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima)
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena) float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura) float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo) float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
float flicker{0.0F}; // Parpadeo de fósforo CRT ~50 Hz (0.0 = off, 1.0 = máximo)
}; };
// --- Variables globales --- // --- Variables globales ---

View File

@@ -2,22 +2,22 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include "core/audio/audio.hpp" // Para Audio #include "core/audio/audio.hpp" // Para Audio
#include "core/input/global_inputs.hpp" // Para check #include "core/input/global_inputs.hpp" // Para check
#include "core/input/input.hpp" // Para Input #include "core/input/input.hpp" // Para Input
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/pixel_reveal.hpp" // Para PixelReveal #include "core/rendering/pixel_reveal.hpp" // Para PixelReveal
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/text.hpp" // Para Text, Text::CENTER_FLAG, Text::COLOR_FLAG #include "core/rendering/text.hpp" // Para Text, Text::CENTER_FLAG, Text::COLOR_FLAG
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "core/system/global_events.hpp" // Para check #include "core/system/global_events.hpp" // Para check
#include "game/options.hpp" // Para Options, options, OptionsGame, Sectio... #include "game/options.hpp" // Para Options, options, OptionsGame, Sectio...
#include "game/scene_manager.hpp" // Para SceneManager #include "game/scene_manager.hpp" // Para SceneManager
#include "utils/defines.hpp" // Para GAME_SPEED, PlayArea::CENTER_X, PLAY_... #include "utils/defines.hpp" // Para GAME_SPEED, PlayArea::CENTER_X, PLAY_...
#include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/utils.hpp" // Para PaletteColor #include "utils/utils.hpp" // Para PaletteColor
// Destructor // Destructor
Credits::~Credits() = default; Credits::~Credits() = default;
@@ -25,12 +25,12 @@ Credits::~Credits() = default;
// Constructor // Constructor
Credits::Credits() Credits::Credits()
: text_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)), : text_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
shining_sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData("shine.yaml"))), shining_sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData("shine.yaml"))),
delta_timer_(std::make_unique<DeltaTimer>()) { delta_timer_(std::make_unique<DeltaTimer>()) {
// Configura la escena // Configura la escena
SceneManager::current = SceneManager::Scene::CREDITS; SceneManager::current = SceneManager::Scene::CREDITS;
SceneManager::options = SceneManager::Options::NONE; SceneManager::options = SceneManager::Options::NONE;
shining_sprite_->setPos({194, 174, 8, 8}); shining_sprite_->setPos({.x = 194, .y = 174, .w = 8, .h = 8});
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
fillTexture(); // Escribe el texto en la textura fillTexture(); // Escribe el texto en la textura
@@ -52,37 +52,37 @@ void Credits::handleInput() {
} }
// Inicializa los textos // Inicializa los textos
void Credits::iniTexts() { void Credits::iniTexts() { // NOLINT(readability-convert-member-functions-to-static)
auto* loc = Locale::get(); auto* loc = Locale::get();
texts_.clear(); texts_.clear();
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.instructions"), static_cast<Uint8>(PaletteColor::YELLOW)}); texts_.push_back({.label = loc->get("credits.instructions"), .color = static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.l0"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.l0"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.l1"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.l1"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.l2"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.l2"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.keys"), static_cast<Uint8>(PaletteColor::YELLOW)}); texts_.push_back({.label = loc->get("credits.keys"), .color = static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.keys_move"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.keys_move"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.f8"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.f8"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.f11"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.f11"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.f1f2"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.f1f2"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.f3"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.f3"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.f9"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.f9"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.author"), static_cast<Uint8>(PaletteColor::YELLOW)}); texts_.push_back({.label = loc->get("credits.author"), .color = static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({loc->get("credits.date"), static_cast<Uint8>(PaletteColor::YELLOW)}); texts_.push_back({.label = loc->get("credits.date"), .color = static_cast<Uint8>(PaletteColor::YELLOW)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({loc->get("credits.love"), static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = loc->get("credits.love"), .color = static_cast<Uint8>(PaletteColor::WHITE)});
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)}); texts_.push_back({.label = "", .color = static_cast<Uint8>(PaletteColor::WHITE)});
} }
// Escribe el texto en la textura // Escribe el texto en la textura

View File

@@ -2,10 +2,10 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
class SurfaceAnimatedSprite; // lines 11-11 class AnimatedSprite; // lines 11-11
class Surface; class Surface;
class PixelReveal; class PixelReveal;
class DeltaTimer; class DeltaTimer;
@@ -14,7 +14,7 @@ class Credits {
public: public:
// --- Constructor y Destructor --- // --- Constructor y Destructor ---
Credits(); Credits();
~Credits(); ~Credits(); // NOLINT(modernize-use-equals-default, performance-trivially-destructible) -- defined in .cpp for unique_ptr with forward declarations
// --- Bucle principal --- // --- Bucle principal ---
void run(); void run();
@@ -64,9 +64,9 @@ class Credits {
// --- Variables miembro --- // --- Variables miembro ---
// Recursos gráficos // Recursos gráficos
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
std::unique_ptr<PixelReveal> pixel_reveal_; // Efecto de revelado pixel a pixel std::unique_ptr<PixelReveal> pixel_reveal_; // Efecto de revelado pixel a pixel
std::shared_ptr<SurfaceAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón std::shared_ptr<AnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
// Temporizadores y estado // Temporizadores y estado
std::unique_ptr<DeltaTimer> delta_timer_; // Temporizador delta para time-based update std::unique_ptr<DeltaTimer> delta_timer_; // Temporizador delta para time-based update

View File

@@ -8,8 +8,8 @@
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/pixel_reveal.hpp" // Para PixelReveal #include "core/rendering/pixel_reveal.hpp" // Para PixelReveal
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/sprite/sprite.hpp" // Para SSprite
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/surface_sprite.hpp" // Para SSprite
#include "core/rendering/text.hpp" // Para Text, TEXT_STROKE #include "core/rendering/text.hpp" // Para Text, TEXT_STROKE
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "core/system/global_events.hpp" // Para check #include "core/system/global_events.hpp" // Para check
@@ -18,6 +18,9 @@
#include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/utils.hpp" // Para PaletteColor #include "utils/utils.hpp" // Para PaletteColor
// Destructor
Ending::~Ending() = default;
// Constructor // Constructor
Ending::Ending() Ending::Ending()
: delta_timer_(std::make_unique<DeltaTimer>()) { : delta_timer_(std::make_unique<DeltaTimer>()) {
@@ -31,9 +34,6 @@ Ending::Ending()
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK)); // Cambia el color del borde
} }
// Destructor
Ending::~Ending() = default;
// Actualiza el objeto // Actualiza el objeto
void Ending::update() { void Ending::update() {
const float DELTA_TIME = delta_timer_->tick(); const float DELTA_TIME = delta_timer_->tick();
@@ -170,39 +170,39 @@ void Ending::updateState(float delta_time) {
} }
// Inicializa los textos // Inicializa los textos
void Ending::iniTexts() { void Ending::iniTexts() { // NOLINT(readability-convert-member-functions-to-static)
// Vector con los textos (traducidos según el idioma activo) // Vector con los textos (traducidos según el idioma activo)
std::vector<TextAndPosition> texts; std::vector<TextAndPosition> texts;
auto* loc = Locale::get(); auto* loc = Locale::get();
// Escena #0 // Escena #0
texts.push_back({loc->get("ending.t0"), 32}); texts.push_back({.caption = loc->get("ending.t0"), .pos = 32});
texts.push_back({loc->get("ending.t1"), 42}); texts.push_back({.caption = loc->get("ending.t1"), .pos = 42});
texts.push_back({loc->get("ending.t2"), 142}); texts.push_back({.caption = loc->get("ending.t2"), .pos = 142});
texts.push_back({loc->get("ending.t3"), 152}); texts.push_back({.caption = loc->get("ending.t3"), .pos = 152});
// Escena #1 // Escena #1
texts.push_back({loc->get("ending.t4"), 1}); texts.push_back({.caption = loc->get("ending.t4"), .pos = 1});
texts.push_back({loc->get("ending.t5"), 11}); texts.push_back({.caption = loc->get("ending.t5"), .pos = 11});
texts.push_back({loc->get("ending.t6"), 21}); texts.push_back({.caption = loc->get("ending.t6"), .pos = 21});
texts.push_back({loc->get("ending.t7"), 161}); texts.push_back({.caption = loc->get("ending.t7"), .pos = 161});
texts.push_back({loc->get("ending.t8"), 171}); texts.push_back({.caption = loc->get("ending.t8"), .pos = 171});
texts.push_back({loc->get("ending.t9"), 181}); texts.push_back({.caption = loc->get("ending.t9"), .pos = 181});
// Escena #2 // Escena #2
texts.push_back({loc->get("ending.t10"), 19}); texts.push_back({.caption = loc->get("ending.t10"), .pos = 19});
texts.push_back({loc->get("ending.t11"), 29}); texts.push_back({.caption = loc->get("ending.t11"), .pos = 29});
// Escena #3 // Escena #3
texts.push_back({loc->get("ending.t12"), 36}); texts.push_back({.caption = loc->get("ending.t12"), .pos = 36});
texts.push_back({loc->get("ending.t13"), 46}); texts.push_back({.caption = loc->get("ending.t13"), .pos = 46});
// Escena #4 // Escena #4
texts.push_back({loc->get("ending.t14"), 36}); texts.push_back({.caption = loc->get("ending.t14"), .pos = 36});
texts.push_back({loc->get("ending.t15"), 46}); texts.push_back({.caption = loc->get("ending.t15"), .pos = 46});
texts.push_back({loc->get("ending.t16"), 158}); texts.push_back({.caption = loc->get("ending.t16"), .pos = 158});
// Crea los sprites // Crea los sprites
sprite_texts_.clear(); sprite_texts_.clear();
@@ -224,7 +224,7 @@ void Ending::iniTexts() {
text->writeDX(Text::STROKE_FLAG, 2, 2, txt.caption, 1, text_color, 2, shadow_color); text->writeDX(Text::STROKE_FLAG, 2, 2, txt.caption, 1, text_color, 2, shadow_color);
// Crea el sprite // Crea el sprite
st.image_sprite = std::make_shared<SurfaceSprite>(st.image_surface, 0, 0, st.image_surface->getWidth(), st.image_surface->getHeight()); st.image_sprite = std::make_shared<Sprite>(st.image_surface, 0, 0, st.image_surface->getWidth(), st.image_surface->getHeight());
st.pos_x = static_cast<int>((Options::game.width - st.image_surface->getWidth()) / 2); st.pos_x = static_cast<int>((Options::game.width - st.image_surface->getWidth()) / 2);
st.pos_y = txt.pos; st.pos_y = txt.pos;
st.image_sprite->setPosition(st.pos_x, st.pos_y); st.image_sprite->setPosition(st.pos_x, st.pos_y);
@@ -242,11 +242,11 @@ void Ending::iniPics() {
// Vector con las rutas y la posición // Vector con las rutas y la posición
std::vector<TextAndPosition> pics; std::vector<TextAndPosition> pics;
pics.push_back({"ending1.gif", 48}); pics.push_back({.caption = "ending1.gif", .pos = 48});
pics.push_back({"ending2.gif", 26}); pics.push_back({.caption = "ending2.gif", .pos = 26});
pics.push_back({"ending3.gif", 29}); pics.push_back({.caption = "ending3.gif", .pos = 29});
pics.push_back({"ending4.gif", 63}); pics.push_back({.caption = "ending4.gif", .pos = 63});
pics.push_back({"ending5.gif", 53}); pics.push_back({.caption = "ending5.gif", .pos = 53});
// Crea los sprites // Crea los sprites
sprite_pics_.clear(); sprite_pics_.clear();
@@ -263,7 +263,7 @@ void Ending::iniPics() {
// Crea el sprite // Crea el sprite
sp.pos_x = static_cast<int>((Options::game.width - WIDTH) / 2); sp.pos_x = static_cast<int>((Options::game.width - WIDTH) / 2);
sp.pos_y = pic.pos; sp.pos_y = pic.pos;
sp.image_sprite = std::make_shared<SurfaceSprite>(sp.image_surface, 0, 0, WIDTH, HEIGHT); sp.image_sprite = std::make_shared<Sprite>(sp.image_surface, 0, 0, WIDTH, HEIGHT);
sp.image_sprite->setPosition(sp.pos_x, sp.pos_y); sp.image_sprite->setPosition(sp.pos_x, sp.pos_y);
// Crea el efecto de revelado pixel a pixel // Crea el efecto de revelado pixel a pixel
@@ -274,7 +274,7 @@ void Ending::iniPics() {
} }
// Inicializa las escenas // Inicializa las escenas
void Ending::iniScenes() { void Ending::iniScenes() { // NOLINT(readability-convert-member-functions-to-static)
// Variable para los tiempos // Variable para los tiempos
int trigger; int trigger;
constexpr int LAPSE = 80; constexpr int LAPSE = 80;
@@ -291,13 +291,13 @@ void Ending::iniScenes() {
sc.text_index.clear(); sc.text_index.clear();
trigger = 85 * 2; trigger = 85 * 2;
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({0, trigger}); sc.text_index.push_back({.index = 0, .trigger = trigger});
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({1, trigger}); sc.text_index.push_back({.index = 1, .trigger = trigger});
trigger += LAPSE * 3; trigger += LAPSE * 3;
sc.text_index.push_back({2, trigger}); sc.text_index.push_back({.index = 2, .trigger = trigger});
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({3, trigger}); sc.text_index.push_back({.index = 3, .trigger = trigger});
scenes_.push_back(sc); scenes_.push_back(sc);
// Crea la escena #1 // Crea la escena #1
@@ -306,17 +306,17 @@ void Ending::iniScenes() {
sc.text_index.clear(); sc.text_index.clear();
trigger = 140 * 2; trigger = 140 * 2;
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({4, trigger}); sc.text_index.push_back({.index = 4, .trigger = trigger});
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({5, trigger}); sc.text_index.push_back({.index = 5, .trigger = trigger});
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({6, trigger}); sc.text_index.push_back({.index = 6, .trigger = trigger});
trigger += LAPSE * 3; trigger += LAPSE * 3;
sc.text_index.push_back({7, trigger}); sc.text_index.push_back({.index = 7, .trigger = trigger});
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({8, trigger}); sc.text_index.push_back({.index = 8, .trigger = trigger});
trigger += LAPSE * 3; trigger += LAPSE * 3;
sc.text_index.push_back({9, trigger}); sc.text_index.push_back({.index = 9, .trigger = trigger});
scenes_.push_back(sc); scenes_.push_back(sc);
// Crea la escena #2 // Crea la escena #2
@@ -325,9 +325,9 @@ void Ending::iniScenes() {
sc.text_index.clear(); sc.text_index.clear();
trigger = 148 / 2; trigger = 148 / 2;
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({10, trigger}); sc.text_index.push_back({.index = 10, .trigger = trigger});
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({11, trigger}); sc.text_index.push_back({.index = 11, .trigger = trigger});
scenes_.push_back(sc); scenes_.push_back(sc);
// Crea la escena #3 // Crea la escena #3
@@ -336,9 +336,9 @@ void Ending::iniScenes() {
sc.text_index.clear(); sc.text_index.clear();
trigger = 87 / 2; trigger = 87 / 2;
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({12, trigger}); sc.text_index.push_back({.index = 12, .trigger = trigger});
trigger += LAPSE / 2; trigger += LAPSE / 2;
sc.text_index.push_back({13, trigger}); sc.text_index.push_back({.index = 13, .trigger = trigger});
scenes_.push_back(sc); scenes_.push_back(sc);
// Crea la escena #4 // Crea la escena #4
@@ -347,11 +347,11 @@ void Ending::iniScenes() {
sc.text_index.clear(); sc.text_index.clear();
trigger = 91 * 2; trigger = 91 * 2;
trigger += LAPSE; trigger += LAPSE;
sc.text_index.push_back({14, trigger}); sc.text_index.push_back({.index = 14, .trigger = trigger});
trigger += LAPSE * 2; trigger += LAPSE * 2;
sc.text_index.push_back({15, trigger}); sc.text_index.push_back({.index = 15, .trigger = trigger});
trigger += LAPSE * 3; trigger += LAPSE * 3;
sc.text_index.push_back({16, trigger}); sc.text_index.push_back({.index = 16, .trigger = trigger});
scenes_.push_back(sc); scenes_.push_back(sc);
} }

View File

@@ -2,11 +2,11 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
class SurfaceSprite; // lines 8-8 class Sprite; // lines 8-8
class Surface; // lines 9-9 class Surface; // lines 9-9
class PixelReveal; class PixelReveal;
class DeltaTimer; class DeltaTimer;
@@ -14,7 +14,7 @@ class Ending {
public: public:
// --- Constructor y Destructor --- // --- Constructor y Destructor ---
Ending(); Ending();
~Ending(); ~Ending(); // NOLINT(modernize-use-equals-default, performance-trivially-destructible) -- defined in .cpp for unique_ptr with forward declarations
// --- Bucle principal --- // --- Bucle principal ---
void run(); void run();
@@ -33,11 +33,11 @@ class Ending {
// --- Estructuras --- // --- Estructuras ---
struct EndingSurface { struct EndingSurface {
std::shared_ptr<Surface> image_surface; // Surface a mostrar std::shared_ptr<Surface> image_surface; // Surface a mostrar
std::shared_ptr<SurfaceSprite> image_sprite; // SSprite para mostrar la textura std::shared_ptr<Sprite> image_sprite; // SSprite para mostrar la textura
std::unique_ptr<PixelReveal> pixel_reveal; // Efecto de revelado pixel a pixel std::unique_ptr<PixelReveal> pixel_reveal; // Efecto de revelado pixel a pixel
int pos_x{0}; // Posición X de renderizado int pos_x{0}; // Posición X de renderizado
int pos_y{0}; // Posición Y de renderizado int pos_y{0}; // Posición Y de renderizado
}; };
struct TextAndPosition { struct TextAndPosition {

View File

@@ -4,22 +4,22 @@
#include <algorithm> // Para max, replace #include <algorithm> // Para max, replace
#include "core/audio/audio.hpp" // Para Audio #include "core/audio/audio.hpp" // Para Audio
#include "core/input/global_inputs.hpp" // Para check #include "core/input/global_inputs.hpp" // Para check
#include "core/input/input.hpp" // Para Input #include "core/input/input.hpp" // Para Input
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/sprite/dissolve_sprite.hpp" // Para SurfaceDissolveSprite
#include "core/rendering/surface_dissolve_sprite.hpp" // Para SurfaceDissolveSprite #include "core/rendering/sprite/moving_sprite.hpp" // Para SMovingSprite
#include "core/rendering/surface_moving_sprite.hpp" // Para SMovingSprite #include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/text.hpp" // Para Text #include "core/rendering/text.hpp" // Para Text
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "core/system/global_events.hpp" // Para check #include "core/system/global_events.hpp" // Para check
#include "game/options.hpp" // Para Options, options, OptionsGame, Sectio... #include "game/options.hpp" // Para Options, options, OptionsGame, Sectio...
#include "game/scene_manager.hpp" // Para SceneManager #include "game/scene_manager.hpp" // Para SceneManager
#include "utils/defines.hpp" // Para GameCanvas::CENTER_X, GameCanvas::CENTER_Y #include "utils/defines.hpp" // Para GameCanvas::CENTER_X, GameCanvas::CENTER_Y
#include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/utils.hpp" // Para PaletteColor, stringToColor #include "utils/utils.hpp" // Para PaletteColor, stringToColor
// Constructor // Constructor
Ending2::Ending2() Ending2::Ending2()
@@ -268,7 +268,7 @@ void Ending2::loadSprites() {
// Carga los sprites // Carga los sprites
for (const auto& file : sprite_list_) { for (const auto& file : sprite_list_) {
const auto& animation_data = Resource::Cache::get()->getAnimationData(file + ".yaml"); const auto& animation_data = Resource::Cache::get()->getAnimationData(file + ".yaml");
sprites_.emplace_back(std::make_shared<SurfaceDissolveSprite>(animation_data)); sprites_.emplace_back(std::make_shared<DissolveSprite>(animation_data));
sprites_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::RED)); sprites_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::RED));
sprites_.back()->setProgress(1.0F); // comença invisible sprites_.back()->setProgress(1.0F); // comença invisible
sprite_max_width_ = std::max(sprites_.back()->getWidth(), sprite_max_width_); sprite_max_width_ = std::max(sprites_.back()->getWidth(), sprite_max_width_);
@@ -374,7 +374,7 @@ void Ending2::renderTexts() {
} }
// Coloca los sprites en su sito // Coloca los sprites en su sito
void Ending2::placeSprites() { void Ending2::placeSprites() const {
for (int i = 0; i < static_cast<int>(sprites_.size()); ++i) { for (int i = 0; i < static_cast<int>(sprites_.size()); ++i) {
const float X = i % 2 == 0 ? FIRST_COL : SECOND_COL; const float X = i % 2 == 0 ? FIRST_COL : SECOND_COL;
const float Y = ((i / 1) * (sprite_max_height_ + DIST_SPRITE_TEXT + Resource::Cache::get()->getText("smb2")->getCharacterSize() + DIST_SPRITE_SPRITE)) + Options::game.height + INITIAL_Y_OFFSET; const float Y = ((i / 1) * (sprite_max_height_ + DIST_SPRITE_TEXT + Resource::Cache::get()->getText("smb2")->getCharacterSize() + DIST_SPRITE_SPRITE)) + Options::game.height + INITIAL_Y_OFFSET;
@@ -383,7 +383,7 @@ void Ending2::placeSprites() {
const float DX = -(W / 2); const float DX = -(W / 2);
const float DY = sprite_max_height_ - H; const float DY = sprite_max_height_ - H;
sprites_.at(i)->setPos({X + DX, Y + DY, W, H}); sprites_.at(i)->setPos({.x = X + DX, .y = Y + DY, .w = W, .h = H});
sprites_.at(i)->setVelY(SPRITE_DESP_SPEED); sprites_.at(i)->setVelY(SPRITE_DESP_SPEED);
} }
@@ -395,7 +395,7 @@ void Ending2::placeSprites() {
} }
// Crea los sprites con las texturas con los textos // Crea los sprites con las texturas con los textos
void Ending2::createSpriteTexts() { void Ending2::createSpriteTexts() { // NOLINT(readability-convert-member-functions-to-static)
// Crea los sprites de texto a partir de la lista // Crea los sprites de texto a partir de la lista
for (size_t i = 0; i < sprite_list_.size(); ++i) { for (size_t i = 0; i < sprite_list_.size(); ++i) {
auto text = Resource::Cache::get()->getText("smb2"); auto text = Resource::Cache::get()->getText("smb2");
@@ -404,7 +404,7 @@ void Ending2::createSpriteTexts() {
std::string txt = sprite_list_[i]; std::string txt = sprite_list_[i];
std::ranges::replace(txt, '_', ' '); // Reemplaza '_' por ' ' std::ranges::replace(txt, '_', ' '); // Reemplaza '_' por ' '
if (txt == "player") { if (txt == "player") {
txt = Locale::get()->get("ending2.jaildoctor"); // Reemplaza "player" por nombre localizado txt = Locale::get()->get("ending2.jaildoctor"); // NOLINT(readability-static-accessed-through-instance) Reemplaza "player" por nombre localizado
} }
// Calcula las dimensiones del texto // Calcula las dimensiones del texto
@@ -426,8 +426,8 @@ void Ending2::createSpriteTexts() {
text->write(0, 0, txt); text->write(0, 0, txt);
// Crea el sprite // Crea el sprite
SDL_FRect pos = {X, Y, W, H}; SDL_FRect pos = {.x = X, .y = Y, .w = W, .h = H};
sprite_texts_.emplace_back(std::make_shared<SurfaceDissolveSprite>(surface, pos)); sprite_texts_.emplace_back(std::make_shared<DissolveSprite>(surface, pos));
sprite_texts_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::WHITE)); sprite_texts_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::WHITE));
sprite_texts_.back()->setProgress(1.0F); // comença invisible sprite_texts_.back()->setProgress(1.0F); // comença invisible
sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED); sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED);
@@ -436,7 +436,7 @@ void Ending2::createSpriteTexts() {
} }
// Crea los sprites con las texturas con los textos del final // Crea los sprites con las texturas con los textos del final
void Ending2::createTexts() { void Ending2::createTexts() { // NOLINT(readability-convert-member-functions-to-static)
// Crea los primeros textos // Crea los primeros textos
std::vector<std::string> list; std::vector<std::string> list;
list.emplace_back(Locale::get()->get("ending2.starring")); list.emplace_back(Locale::get()->get("ending2.starring"));
@@ -459,8 +459,8 @@ void Ending2::createTexts() {
text->write(0, 0, list[i]); text->write(0, 0, list[i]);
// Crea el sprite // Crea el sprite
SDL_FRect pos = {X + DX, Y, W, H}; SDL_FRect pos = {.x = X + DX, .y = Y, .w = W, .h = H};
texts_.emplace_back(std::make_shared<SurfaceDissolveSprite>(surface, pos)); texts_.emplace_back(std::make_shared<DissolveSprite>(surface, pos));
texts_.back()->setProgress(1.0F); // comença invisible texts_.back()->setProgress(1.0F); // comença invisible
texts_.back()->setVelY(SPRITE_DESP_SPEED); texts_.back()->setVelY(SPRITE_DESP_SPEED);
Screen::get()->setRendererSurface(previuos_renderer); Screen::get()->setRendererSurface(previuos_renderer);
@@ -489,8 +489,8 @@ void Ending2::createTexts() {
text->write(0, 0, list[i]); text->write(0, 0, list[i]);
// Crea el sprite // Crea el sprite
SDL_FRect pos = {X + DX, Y, W, H}; SDL_FRect pos = {.x = X + DX, .y = Y, .w = W, .h = H};
texts_.emplace_back(std::make_shared<SurfaceDissolveSprite>(surface, pos)); texts_.emplace_back(std::make_shared<DissolveSprite>(surface, pos));
texts_.back()->setProgress(1.0F); // comença invisible texts_.back()->setProgress(1.0F); // comença invisible
texts_.back()->setVelY(SPRITE_DESP_SPEED); texts_.back()->setVelY(SPRITE_DESP_SPEED);
Screen::get()->setRendererSurface(previuos_renderer); Screen::get()->setRendererSurface(previuos_renderer);

View File

@@ -6,10 +6,10 @@
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
#include "core/rendering/surface_dissolve_sprite.hpp" // Para SurfaceDissolveSprite #include "core/rendering/sprite/dissolve_sprite.hpp" // Para SurfaceDissolveSprite
#include "utils/defines.hpp" // Para GameCanvas::WIDTH, GameCanvas::FIRST_QUAR... #include "utils/defines.hpp" // Para GameCanvas::WIDTH, GameCanvas::FIRST_QUAR...
class SurfaceMovingSprite; class MovingSprite;
class DeltaTimer; class DeltaTimer;
class Ending2 { class Ending2 {
@@ -70,17 +70,17 @@ class Ending2 {
void renderSprites(); // Dibuja los sprites void renderSprites(); // Dibuja los sprites
void renderSpriteTexts(); // Dibuja los sprites con el texto void renderSpriteTexts(); // Dibuja los sprites con el texto
void renderTexts(); // Dibuja los sprites con el texto del final void renderTexts(); // Dibuja los sprites con el texto del final
void placeSprites(); // Coloca los sprites en su sitio void placeSprites() const; // Coloca los sprites en su sitio
void createSpriteTexts(); // Crea los sprites con las texturas con los textos void createSpriteTexts(); // Crea los sprites con las texturas con los textos
void createTexts(); // Crea los sprites con las texturas con los textos del final void createTexts(); // Crea los sprites con las texturas con los textos del final
void updateFinalFade(); // Actualiza el fade final void updateFinalFade(); // Actualiza el fade final
// --- Variables miembro --- // --- Variables miembro ---
// Objetos y punteros a recursos // Objetos y punteros a recursos
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprites_; // Vector con todos los sprites a dibujar std::vector<std::shared_ptr<DissolveSprite>> sprites_; // Vector con todos los sprites a dibujar
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites std::vector<std::shared_ptr<DissolveSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
std::vector<std::shared_ptr<SurfaceDissolveSprite>> texts_; // Vector con los sprites de texto std::vector<std::shared_ptr<DissolveSprite>> texts_; // Vector con los sprites de texto
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update
// Variables de estado // Variables de estado
State state_; // Controla el estado de la clase State state_; // Controla el estado de la clase

View File

@@ -94,9 +94,9 @@ void Game::handleInput() {
} }
// Input de pausa solo en estado PLAYING // Input de pausa solo en estado PLAYING
if (Input::get()->checkAction(InputAction::PAUSE, Input::DO_NOT_ALLOW_REPEAT)) { if (Input::get()->checkAction(InputAction::PAUSE, Input::DO_NOT_ALLOW_REPEAT)) { // NOLINT(readability-static-accessed-through-instance)
togglePause(); togglePause();
Notifier::get()->show({paused_ ? Locale::get()->get("game.paused") : Locale::get()->get("game.running")}); Notifier::get()->show({paused_ ? Locale::get()->get("game.paused") : Locale::get()->get("game.running")}); // NOLINT(readability-static-accessed-through-instance)
} }
GlobalInputs::handle(); GlobalInputs::handle();
@@ -371,7 +371,7 @@ void Game::renderPostFadeEnding() {
static void toggleCheat(Options::Cheat::State& cheat, const std::string& label) { 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; cheat = (cheat == Options::Cheat::State::ENABLED) ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED;
const bool ENABLED = (cheat == Options::Cheat::State::ENABLED); const bool ENABLED = (cheat == Options::Cheat::State::ENABLED);
Notifier::get()->show({label + (ENABLED ? Locale::get()->get("game.enabled") : Locale::get()->get("game.disabled"))}, Notifier::Style::DEFAULT, -1, true); Notifier::get()->show({label + (ENABLED ? Locale::get()->get("game.enabled") : Locale::get()->get("game.disabled"))}, Notifier::Style::DEFAULT, -1, true); // NOLINT(readability-static-accessed-through-instance)
} }
// Pasa la información de debug // Pasa la información de debug
@@ -390,7 +390,7 @@ void Game::renderDebugInfo() {
auto surface = Screen::get()->getRendererSurface(); auto surface = Screen::get()->getRendererSurface();
// Borra el marcador // Borra el marcador
SDL_FRect rect = {0, 18 * Tile::SIZE, PlayArea::WIDTH, GameCanvas::HEIGHT - PlayArea::HEIGHT}; SDL_FRect rect = {.x = 0, .y = 18 * Tile::SIZE, .w = PlayArea::WIDTH, .h = GameCanvas::HEIGHT - PlayArea::HEIGHT};
surface->fillRect(&rect, static_cast<Uint8>(PaletteColor::BLACK)); surface->fillRect(&rect, static_cast<Uint8>(PaletteColor::BLACK));
// Pinta la rejilla // Pinta la rejilla
@@ -406,12 +406,12 @@ void Game::renderDebugInfo() {
}*/ }*/
// Pinta el texto // Pinta el texto
Debug::get()->setPos({1, 18 * 8}); Debug::get()->setPos({.x = 1, .y = 18 * 8});
Debug::get()->render(); Debug::get()->render();
} }
// Comprueba los eventos // Comprueba los eventos
void Game::handleDebugEvents(const SDL_Event& event) { void Game::handleDebugEvents(const SDL_Event& event) { // NOLINT(readability-convert-member-functions-to-static)
if (event.type == SDL_EVENT_KEY_DOWN && static_cast<int>(event.key.repeat) == 0) { if (event.type == SDL_EVENT_KEY_DOWN && static_cast<int>(event.key.repeat) == 0) {
switch (event.key.key) { switch (event.key.key) {
case SDLK_R: case SDLK_R:
@@ -435,26 +435,26 @@ void Game::handleDebugEvents(const SDL_Event& event) {
break; break;
case SDLK_1: case SDLK_1:
toggleCheat(Options::cheats.infinite_lives, Locale::get()->get("game.cheat_infinite_lives")); toggleCheat(Options::cheats.infinite_lives, Locale::get()->get("game.cheat_infinite_lives")); // NOLINT(readability-static-accessed-through-instance)
player_->setColor(); player_->setColor();
break; break;
case SDLK_2: case SDLK_2:
toggleCheat(Options::cheats.invincible, Locale::get()->get("game.cheat_invincible")); toggleCheat(Options::cheats.invincible, Locale::get()->get("game.cheat_invincible")); // NOLINT(readability-static-accessed-through-instance)
player_->setColor(); player_->setColor();
break; break;
case SDLK_3: case SDLK_3:
toggleCheat(Options::cheats.jail_is_open, Locale::get()->get("game.cheat_jail_open")); toggleCheat(Options::cheats.jail_is_open, Locale::get()->get("game.cheat_jail_open")); // NOLINT(readability-static-accessed-through-instance)
break; break;
case SDLK_7: case SDLK_7:
Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c11")}, Notifier::Style::CHEEVO, -1, false, "F7"); Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c11")}, Notifier::Style::CHEEVO, -1, false, "F7"); // NOLINT(readability-static-accessed-through-instance)
break; break;
case SDLK_0: case SDLK_0:
Debug::get()->toggleEnabled(); Debug::get()->toggleEnabled();
Notifier::get()->show({Debug::get()->isEnabled() ? Locale::get()->get("game.debug_enabled") : Locale::get()->get("game.debug_disabled")}); Notifier::get()->show({Debug::get()->isEnabled() ? Locale::get()->get("game.debug_enabled") : Locale::get()->get("game.debug_disabled")}); // NOLINT(readability-static-accessed-through-instance)
room_->redrawMap(); room_->redrawMap();
Options::cheats.invincible = static_cast<Options::Cheat::State>(Debug::get()->isEnabled()); Options::cheats.invincible = static_cast<Options::Cheat::State>(Debug::get()->isEnabled());
player_->setColor(); player_->setColor();
@@ -556,7 +556,7 @@ auto Game::changeRoom(const std::string& room_path) -> bool {
} }
// Verifica que exista el fichero que se va a cargar // Verifica que exista el fichero que se va a cargar
if (!Resource::List::get()->get(room_path).empty()) { if (!Resource::List::get()->get(room_path).empty()) { // NOLINT(readability-static-accessed-through-instance)
// Crea un objeto habitación nuevo a partir del fichero // Crea un objeto habitación nuevo a partir del fichero
room_ = std::make_shared<Room>(room_path, scoreboard_data_); room_ = std::make_shared<Room>(room_path, scoreboard_data_);
@@ -655,7 +655,7 @@ void Game::killPlayer() {
} }
// Pone el color del marcador en función del color del borde de la habitación // Pone el color del marcador en función del color del borde de la habitación
void Game::setScoreBoardColor() { void Game::setScoreBoardColor() { // NOLINT(readability-convert-member-functions-to-static)
// Obtiene el color del borde // Obtiene el color del borde
const Uint8 BORDER_COLOR = room_->getBorderColor(); const Uint8 BORDER_COLOR = room_->getBorderColor();
@@ -734,7 +734,7 @@ void Game::checkRestoringJail(float delta_time) {
} }
// Inicializa el diccionario de las estadísticas // Inicializa el diccionario de las estadísticas
void Game::initStats() { void Game::initStats() { // NOLINT(readability-convert-member-functions-to-static)
auto list = Resource::Cache::get()->getRooms(); auto list = Resource::Cache::get()->getRooms();
for (const auto& room : list) { for (const auto& room : list) {
@@ -745,7 +745,7 @@ void Game::initStats() {
} }
// Crea la textura con el nombre de la habitación // Crea la textura con el nombre de la habitación
void Game::fillRoomNameTexture() { void Game::fillRoomNameTexture() { // NOLINT(readability-convert-member-functions-to-static)
// Pone la textura como destino de renderizado // Pone la textura como destino de renderizado
auto previuos_renderer = Screen::get()->getRendererSurface(); auto previuos_renderer = Screen::get()->getRendererSurface();
Screen::get()->setRendererSurface(room_name_surface_); Screen::get()->setRendererSurface(room_name_surface_);
@@ -762,7 +762,7 @@ void Game::fillRoomNameTexture() {
} }
// Comprueba algunos logros // Comprueba algunos logros
void Game::checkSomeCheevos() { void Game::checkSomeCheevos() { // NOLINT(readability-convert-member-functions-to-static)
auto* cheevos = Cheevos::get(); auto* cheevos = Cheevos::get();
// Logros sobre la cantidad de items // Logros sobre la cantidad de items
@@ -796,7 +796,7 @@ void Game::checkSomeCheevos() {
} }
// Comprueba los logros de completar el juego // Comprueba los logros de completar el juego
void Game::checkEndGameCheevos() { void Game::checkEndGameCheevos() { // NOLINT(readability-convert-member-functions-to-static)
auto* cheevos = Cheevos::get(); auto* cheevos = Cheevos::get();
// "Complete the game" // "Complete the game"
@@ -820,7 +820,7 @@ void Game::checkEndGameCheevos() {
} }
// Inicializa al jugador // Inicializa al jugador
void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) { void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) { // NOLINT(readability-convert-member-functions-to-static)
std::string player_animations = Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.yaml" : "player.yaml"; std::string player_animations = Options::cheats.alternate_skin == Options::Cheat::State::ENABLED ? "player2.yaml" : "player.yaml";
const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = player_animations, .room = std::move(room)}; const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = player_animations, .room = std::move(room)};
player_ = std::make_shared<Player>(PLAYER); player_ = std::make_shared<Player>(PLAYER);

View File

@@ -5,25 +5,25 @@
#include <algorithm> // Para min, max #include <algorithm> // Para min, max
#include <string> // Para basic_string, operator+, to_string #include <string> // Para basic_string, operator+, to_string
#include "core/audio/audio.hpp" // Para Audio #include "core/audio/audio.hpp" // Para Audio
#include "core/input/global_inputs.hpp" // Para check #include "core/input/global_inputs.hpp" // Para check
#include "core/input/input.hpp" // Para Input #include "core/input/input.hpp" // Para Input
#include "core/locale/locale.hpp" // Para Locale #include "core/locale/locale.hpp" // Para Locale
#include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite #include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
#include "core/rendering/text.hpp" // Para Text::CENTER_FLAG, Text::COLOR_FLAG, Text #include "core/rendering/text.hpp" // Para Text::CENTER_FLAG, Text::COLOR_FLAG, Text
#include "core/resources/resource_cache.hpp" // Para Resource #include "core/resources/resource_cache.hpp" // Para Resource
#include "core/system/global_events.hpp" // Para check #include "core/system/global_events.hpp" // Para check
#include "game/options.hpp" // Para Options, options, OptionsStats, Secti... #include "game/options.hpp" // Para Options, options, OptionsStats, Secti...
#include "game/scene_manager.hpp" // Para SceneManager #include "game/scene_manager.hpp" // Para SceneManager
#include "utils/defines.hpp" // Para GameCanvas::CENTER_X #include "utils/defines.hpp" // Para GameCanvas::CENTER_X
#include "utils/delta_timer.hpp" // Para DeltaTimer #include "utils/delta_timer.hpp" // Para DeltaTimer
#include "utils/utils.hpp" // Para PaletteColor, stringToColor #include "utils/utils.hpp" // Para PaletteColor, stringToColor
// Constructor // Constructor
GameOver::GameOver() GameOver::GameOver()
: player_sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData("player_game_over.yaml"))), : player_sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData("player_game_over.yaml"))),
tv_sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData("tv.yaml"))), tv_sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData("tv.yaml"))),
delta_timer_(std::make_shared<DeltaTimer>()) { delta_timer_(std::make_shared<DeltaTimer>()) {
SceneManager::current = SceneManager::Scene::GAME_OVER; SceneManager::current = SceneManager::Scene::GAME_OVER;
SceneManager::options = SceneManager::Options::NONE; SceneManager::options = SceneManager::Options::NONE;
@@ -70,7 +70,7 @@ void GameOver::render() {
// Escribe el texto de GAME OVER // Escribe el texto de GAME OVER
auto* loc = Locale::get(); auto* loc = Locale::get();
text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y, loc->get("game_over.title"), 1, color_); text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y, loc->get("game_over.title"), 1, color_); // NOLINT(readability-static-accessed-through-instance)
// Dibuja los sprites (ya posicionados en el constructor, solo ajustamos Y) // Dibuja los sprites (ya posicionados en el constructor, solo ajustamos Y)
player_sprite_->setPosY(TEXT_Y + SPRITE_Y_OFFSET); player_sprite_->setPosY(TEXT_Y + SPRITE_Y_OFFSET);
@@ -80,11 +80,11 @@ void GameOver::render() {
// Escribe el texto con las habitaciones y los items // Escribe el texto con las habitaciones y los items
const std::string ITEMS_TEXT = std::to_string(Options::stats.items / 100) + std::to_string((Options::stats.items % 100) / 10) + std::to_string(Options::stats.items % 10); const std::string ITEMS_TEXT = std::to_string(Options::stats.items / 100) + std::to_string((Options::stats.items % 100) / 10) + std::to_string(Options::stats.items % 10);
const std::string ROOMS_TEXT = std::to_string(Options::stats.rooms / 100) + std::to_string((Options::stats.rooms % 100) / 10) + std::to_string(Options::stats.rooms % 10); const std::string ROOMS_TEXT = std::to_string(Options::stats.rooms / 100) + std::to_string((Options::stats.rooms % 100) / 10) + std::to_string(Options::stats.rooms % 10);
text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + ITEMS_Y_OFFSET, loc->get("game_over.items") + ITEMS_TEXT, 1, color_); text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + ITEMS_Y_OFFSET, loc->get("game_over.items") + ITEMS_TEXT, 1, color_); // NOLINT(readability-static-accessed-through-instance)
text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + ROOMS_Y_OFFSET, loc->get("game_over.rooms") + ROOMS_TEXT, 1, color_); text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + ROOMS_Y_OFFSET, loc->get("game_over.rooms") + ROOMS_TEXT, 1, color_); // NOLINT(readability-static-accessed-through-instance)
// Escribe el texto con "Tu peor pesadilla" // Escribe el texto con "Tu peor pesadilla"
text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + NIGHTMARE_TITLE_Y_OFFSET, loc->get("game_over.worst_nightmare"), 1, color_); text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + NIGHTMARE_TITLE_Y_OFFSET, loc->get("game_over.worst_nightmare"), 1, color_); // NOLINT(readability-static-accessed-through-instance)
text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + NIGHTMARE_TEXT_Y_OFFSET, Options::stats.worst_nightmare, 1, color_); text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, TEXT_Y + NIGHTMARE_TEXT_Y_OFFSET, Options::stats.worst_nightmare, 1, color_);
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla

Some files were not shown because too many files have changed in this diff Show More