neteja tidy a source/core i encamina Texture::loadFromFile pel ResourceHelper

This commit is contained in:
2026-05-14 20:22:54 +02:00
parent 88fa3f296f
commit 1912200b21
40 changed files with 699 additions and 578 deletions
+10 -4
View File
@@ -51,7 +51,7 @@ void Audio::update() {
JA_Update(); JA_Update();
// Sincronizar estado: detectar cuando la música se para (ej. fade-out completado) // Sincronizar estado: detectar cuando la música se para (ej. fade-out completado)
if (instance && instance->music_.state == MusicState::PLAYING && JA_GetMusicState() != JA_MUSIC_PLAYING) { if ((instance != nullptr) && instance->music_.state == MusicState::PLAYING && JA_GetMusicState() != JA_MUSIC_PLAYING) {
instance->music_.state = MusicState::STOPPED; instance->music_.state = MusicState::STOPPED;
} }
} }
@@ -65,10 +65,14 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa
return; return;
} }
if (!music_enabled_) return; if (!music_enabled_) {
return;
}
auto* resource = AudioResource::getMusic(name); auto* resource = AudioResource::getMusic(name);
if (resource == nullptr) return; if (resource == nullptr) {
return;
}
if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) {
JA_CrossfadeMusic(resource, crossfade_ms, loop); JA_CrossfadeMusic(resource, crossfade_ms, loop);
@@ -86,7 +90,9 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa
// Reproduce la música por puntero (con crossfade opcional) // Reproduce la música por puntero (con crossfade opcional)
void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) { void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) {
if (!music_enabled_ || music == nullptr) return; if (!music_enabled_ || music == nullptr) {
return;
}
if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) { if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) {
JA_CrossfadeMusic(music, crossfade_ms, loop); JA_CrossfadeMusic(music, crossfade_ms, loop);
+1 -1
View File
@@ -60,7 +60,7 @@ class Audio {
// --- Helpers de conversió per a la capa de presentació --- // --- Helpers de conversió per a la capa de presentació ---
// UI (menús, notificacions) manega enters 0..100; internament viu float 0..1. // UI (menús, notificacions) manega enters 0..100; internament viu float 0..1.
static constexpr auto toPercent(float volume) -> int { static constexpr auto toPercent(float volume) -> int {
return static_cast<int>(volume * 100.0F + 0.5F); return static_cast<int>((volume * 100.0F) + 0.5F);
} }
static constexpr auto fromPercent(int percent) -> float { static constexpr auto fromPercent(int percent) -> float {
return static_cast<float>(percent) / 100.0F; return static_cast<float>(percent) / 100.0F;
+2 -2
View File
@@ -3,11 +3,11 @@
#include "core/resources/resource.h" #include "core/resources/resource.h"
namespace AudioResource { namespace AudioResource {
JA_Music_t* getMusic(const std::string& name) { auto getMusic(const std::string& name) -> JA_Music_t* {
return Resource::get()->getMusic(name); return Resource::get()->getMusic(name);
} }
JA_Sound_t* getSound(const std::string& name) { auto getSound(const std::string& name) -> JA_Sound_t* {
return Resource::get()->getSound(name); return Resource::get()->getSound(name);
} }
} // namespace AudioResource } // namespace AudioResource
+2 -2
View File
@@ -12,6 +12,6 @@ struct JA_Music_t;
struct JA_Sound_t; struct JA_Sound_t;
namespace AudioResource { namespace AudioResource {
JA_Music_t* getMusic(const std::string& name); auto getMusic(const std::string& name) -> JA_Music_t*;
JA_Sound_t* getSound(const std::string& name); auto getSound(const std::string& name) -> JA_Sound_t*;
} // namespace AudioResource } // namespace AudioResource
+218 -117
View File
@@ -19,7 +19,9 @@
// overhead gràcies a EBO, igual que un unique_ptr amb default_delete. // overhead gràcies a EBO, igual que un unique_ptr amb default_delete.
struct SDLFreeDeleter { struct SDLFreeDeleter {
void operator()(Uint8* p) const noexcept { void operator()(Uint8* p) const noexcept {
if (p) SDL_free(p); if (p != nullptr) {
SDL_free(p);
}
} }
}; };
@@ -40,8 +42,10 @@ enum JA_Music_state {
}; };
// --- Struct Definitions --- // --- Struct Definitions ---
#define JA_MAX_SIMULTANEOUS_CHANNELS 20 enum {
#define JA_MAX_GROUPS 2 JA_MAX_SIMULTANEOUS_CHANNELS = 20,
JA_MAX_GROUPS = 2
};
struct JA_Sound_t { struct JA_Sound_t {
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
@@ -84,7 +88,7 @@ inline JA_Music_t* current_music{nullptr};
inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; inline JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
inline SDL_AudioSpec JA_audioSpec{SDL_AUDIO_S16, 2, 48000}; inline SDL_AudioSpec JA_audioSpec{SDL_AUDIO_S16, 2, 48000};
inline float JA_musicVolume{1.0f}; inline float JA_musicVolume{1.0F};
inline float JA_soundVolume[JA_MAX_GROUPS]; inline float JA_soundVolume[JA_MAX_GROUPS];
inline bool JA_musicEnabled{true}; inline bool JA_musicEnabled{true};
inline bool JA_soundEnabled{true}; inline bool JA_soundEnabled{true};
@@ -95,7 +99,7 @@ struct JA_FadeState {
bool active{false}; bool active{false};
Uint64 start_time{0}; Uint64 start_time{0};
int duration_ms{0}; int duration_ms{0};
float initial_volume{0.0f}; float initial_volume{0.0F};
}; };
struct JA_OutgoingMusic { struct JA_OutgoingMusic {
@@ -108,8 +112,8 @@ inline JA_FadeState incoming_fade;
// --- Forward Declarations --- // --- Forward Declarations ---
inline void JA_StopMusic(); inline void JA_StopMusic();
inline void JA_StopChannel(const int channel); inline void JA_StopChannel(int channel);
inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0, const int group = 0); inline auto JA_PlaySoundOnChannel(JA_Sound_t* sound, int channel, int loop = 0, int group = 0) -> int;
inline void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1); inline void JA_CrossfadeMusic(JA_Music_t* music, int crossfade_ms, int loop = -1);
// --- Music streaming internals --- // --- Music streaming internals ---
@@ -120,12 +124,14 @@ static constexpr int JA_MUSIC_BYTES_PER_SAMPLE = 2;
static constexpr int JA_MUSIC_CHUNK_SHORTS = 8192; static constexpr int JA_MUSIC_CHUNK_SHORTS = 8192;
// Umbral d'audio per davant del cursor de reproducció. Mantenim ≥ 0.5 s a // Umbral d'audio per davant del cursor de reproducció. Mantenim ≥ 0.5 s a
// l'SDL_AudioStream per absorbir jitter de frame i evitar underruns. // l'SDL_AudioStream per absorbir jitter de frame i evitar underruns.
static constexpr float JA_MUSIC_LOW_WATER_SECONDS = 0.5f; static constexpr float JA_MUSIC_LOW_WATER_SECONDS = 0.5F;
// Decodifica un chunk del vorbis i el volca a l'stream. Retorna samples // Decodifica un chunk del vorbis i el volca a l'stream. Retorna samples
// decodificats per canal (0 = EOF de l'stream vorbis). // decodificats per canal (0 = EOF de l'stream vorbis).
inline int JA_FeedMusicChunk(JA_Music_t* music) { inline auto JA_FeedMusicChunk(JA_Music_t* music) -> int {
if (!music || !music->vorbis || !music->stream) return 0; if ((music == nullptr) || (music->vorbis == nullptr) || (music->stream == nullptr)) {
return 0;
}
short chunk[JA_MUSIC_CHUNK_SHORTS]; short chunk[JA_MUSIC_CHUNK_SHORTS];
const int num_channels = music->spec.channels; const int num_channels = music->spec.channels;
@@ -134,7 +140,9 @@ inline int JA_FeedMusicChunk(JA_Music_t* music) {
num_channels, num_channels,
chunk, chunk,
JA_MUSIC_CHUNK_SHORTS); JA_MUSIC_CHUNK_SHORTS);
if (samples_per_channel <= 0) return 0; if (samples_per_channel <= 0) {
return 0;
}
const int bytes = samples_per_channel * num_channels * JA_MUSIC_BYTES_PER_SAMPLE; const int bytes = samples_per_channel * num_channels * JA_MUSIC_BYTES_PER_SAMPLE;
SDL_PutAudioStreamData(music->stream, chunk, bytes); SDL_PutAudioStreamData(music->stream, chunk, bytes);
@@ -144,19 +152,25 @@ inline int JA_FeedMusicChunk(JA_Music_t* music) {
// Reompli l'stream fins que tinga ≥ JA_MUSIC_LOW_WATER_SECONDS bufferats. // Reompli l'stream fins que tinga ≥ JA_MUSIC_LOW_WATER_SECONDS bufferats.
// En arribar a EOF del vorbis, aplica el loop (times) o deixa drenar. // En arribar a EOF del vorbis, aplica el loop (times) o deixa drenar.
inline void JA_PumpMusic(JA_Music_t* music) { inline void JA_PumpMusic(JA_Music_t* music) {
if (!music || !music->vorbis || !music->stream) return; if ((music == nullptr) || (music->vorbis == nullptr) || (music->stream == nullptr)) {
return;
}
const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE; const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE;
const int low_water_bytes = static_cast<int>(JA_MUSIC_LOW_WATER_SECONDS * static_cast<float>(bytes_per_second)); const int low_water_bytes = static_cast<int>(JA_MUSIC_LOW_WATER_SECONDS * static_cast<float>(bytes_per_second));
while (SDL_GetAudioStreamAvailable(music->stream) < low_water_bytes) { while (SDL_GetAudioStreamAvailable(music->stream) < low_water_bytes) {
const int decoded = JA_FeedMusicChunk(music); const int decoded = JA_FeedMusicChunk(music);
if (decoded > 0) continue; if (decoded > 0) {
continue;
}
// EOF: si queden loops, rebobinar; si no, tallar i deixar drenar. // EOF: si queden loops, rebobinar; si no, tallar i deixar drenar.
if (music->times != 0) { if (music->times != 0) {
stb_vorbis_seek_start(music->vorbis); stb_vorbis_seek_start(music->vorbis);
if (music->times > 0) music->times--; if (music->times > 0) {
music->times--;
}
} else { } else {
break; break;
} }
@@ -168,14 +182,18 @@ inline void JA_PumpMusic(JA_Music_t* music) {
// streaming: l'stream robat no es pot re-alimentar perquè perd la referència // streaming: l'stream robat no es pot re-alimentar perquè perd la referència
// al seu vorbis decoder. No aplica loop — si el vorbis s'esgota abans, parem. // al seu vorbis decoder. No aplica loop — si el vorbis s'esgota abans, parem.
inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) { inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) {
if (!music || !music->vorbis || !music->stream) return; if ((music == nullptr) || (music->vorbis == nullptr) || (music->stream == nullptr)) {
return;
}
const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE; const int bytes_per_second = music->spec.freq * music->spec.channels * JA_MUSIC_BYTES_PER_SAMPLE;
const int needed_bytes = static_cast<int>((static_cast<int64_t>(duration_ms) * bytes_per_second) / 1000); const int needed_bytes = static_cast<int>((static_cast<int64_t>(duration_ms) * bytes_per_second) / 1000);
while (SDL_GetAudioStreamAvailable(music->stream) < needed_bytes) { while (SDL_GetAudioStreamAvailable(music->stream) < needed_bytes) {
const int decoded = JA_FeedMusicChunk(music); const int decoded = JA_FeedMusicChunk(music);
if (decoded <= 0) break; // EOF: deixem drenar el que hi haja if (decoded <= 0) {
break; // EOF: deixem drenar el que hi haja
}
} }
} }
@@ -183,7 +201,7 @@ inline void JA_PreFillOutgoing(JA_Music_t* music, int duration_ms) {
inline void JA_Update() { inline void JA_Update() {
// --- Outgoing music fade-out (crossfade o fade-out a silencio) --- // --- Outgoing music fade-out (crossfade o fade-out a silencio) ---
if (outgoing_music.stream && outgoing_music.fade.active) { if ((outgoing_music.stream != nullptr) && outgoing_music.fade.active) {
Uint64 now = SDL_GetTicks(); Uint64 now = SDL_GetTicks();
Uint64 elapsed = now - outgoing_music.fade.start_time; Uint64 elapsed = now - outgoing_music.fade.start_time;
if (elapsed >= (Uint64)outgoing_music.fade.duration_ms) { if (elapsed >= (Uint64)outgoing_music.fade.duration_ms) {
@@ -192,12 +210,12 @@ inline void JA_Update() {
outgoing_music.fade.active = false; outgoing_music.fade.active = false;
} else { } else {
float percent = (float)elapsed / (float)outgoing_music.fade.duration_ms; float percent = (float)elapsed / (float)outgoing_music.fade.duration_ms;
SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0f - percent)); SDL_SetAudioStreamGain(outgoing_music.stream, outgoing_music.fade.initial_volume * (1.0F - percent));
} }
} }
// --- Current music --- // --- Current music ---
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) { if (JA_musicEnabled && (current_music != nullptr) && current_music->state == JA_MUSIC_PLAYING) {
// Fade-in (parte de un crossfade) // Fade-in (parte de un crossfade)
if (incoming_fade.active) { if (incoming_fade.active) {
Uint64 now = SDL_GetTicks(); Uint64 now = SDL_GetTicks();
@@ -221,42 +239,59 @@ inline void JA_Update() {
// --- Sound channels --- // --- Sound channels ---
if (JA_soundEnabled) { if (JA_soundEnabled) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) {
if (channels[i].state == JA_CHANNEL_PLAYING) { if (channels[i].state == JA_CHANNEL_PLAYING) {
if (channels[i].times != 0) { if (channels[i].times != 0) {
if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) { if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) {
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer.get(), channels[i].sound->length); SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer.get(), channels[i].sound->length);
if (channels[i].times > 0) channels[i].times--; if (channels[i].times > 0) {
channels[i].times--;
}
} }
} else { } else {
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) JA_StopChannel(i); if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) {
JA_StopChannel(i);
}
}
} }
} }
} }
} }
inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) { inline void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) {
JA_audioSpec = {format, num_channels, freq}; JA_audioSpec = {.format = format, .channels = num_channels, .freq = freq};
if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); if (sdlAudioDevice != 0U) {
SDL_CloseAudioDevice(sdlAudioDevice);
}
sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec); sdlAudioDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &JA_audioSpec);
if (sdlAudioDevice == 0) std::cout << "Failed to initialize SDL audio!" << '\n'; if (sdlAudioDevice == 0) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) channels[i].state = JA_CHANNEL_FREE; std::cout << "Failed to initialize SDL audio!" << '\n';
for (int i = 0; i < JA_MAX_GROUPS; ++i) JA_soundVolume[i] = 0.5f; }
for (auto& channel : channels) {
channel.state = JA_CHANNEL_FREE;
}
for (float& i : JA_soundVolume) {
i = 0.5F;
}
} }
inline void JA_Quit() { inline void JA_Quit() {
if (outgoing_music.stream) { if (outgoing_music.stream != nullptr) {
SDL_DestroyAudioStream(outgoing_music.stream); SDL_DestroyAudioStream(outgoing_music.stream);
outgoing_music.stream = nullptr; outgoing_music.stream = nullptr;
} }
if (sdlAudioDevice) SDL_CloseAudioDevice(sdlAudioDevice); if (sdlAudioDevice != 0U) {
SDL_CloseAudioDevice(sdlAudioDevice);
}
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
// --- Music Functions --- // --- Music Functions ---
inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) { inline auto JA_LoadMusic(const Uint8* buffer, Uint32 length) -> JA_Music_t* {
if (!buffer || length == 0) return nullptr; if ((buffer == nullptr) || length == 0) {
return nullptr;
}
// Allocem el JA_Music_t primer per aprofitar el seu `std::vector<Uint8>` // Allocem el JA_Music_t primer per aprofitar el seu `std::vector<Uint8>`
// com a propietari del OGG comprimit. stb_vorbis guarda un punter // com a propietari del OGG comprimit. stb_vorbis guarda un punter
@@ -270,7 +305,7 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) {
static_cast<int>(length), static_cast<int>(length),
&err, &err,
nullptr); nullptr);
if (!music->vorbis) { if (music->vorbis == nullptr) {
std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << err << ")" << '\n'; std::cout << "JA_LoadMusic: stb_vorbis_open_memory failed (error " << err << ")" << '\n';
delete music; delete music;
return nullptr; return nullptr;
@@ -287,21 +322,25 @@ inline JA_Music_t* JA_LoadMusic(const Uint8* buffer, Uint32 length) {
// Overload amb filename — els callers l'usen per poder comparar la música // Overload amb filename — els callers l'usen per poder comparar la música
// en curs amb JA_GetMusicFilename() i no rearrancar-la si ja és la mateixa. // en curs amb JA_GetMusicFilename() i no rearrancar-la si ja és la mateixa.
inline JA_Music_t* JA_LoadMusic(Uint8* buffer, Uint32 length, const char* filename) { inline auto JA_LoadMusic(Uint8* buffer, Uint32 length, const char* filename) -> JA_Music_t* {
JA_Music_t* music = JA_LoadMusic(static_cast<const Uint8*>(buffer), length); JA_Music_t* music = JA_LoadMusic(static_cast<const Uint8*>(buffer), length);
if (music && filename) music->filename = filename; if ((music != nullptr) && (filename != nullptr)) {
music->filename = filename;
}
return music; return music;
} }
inline JA_Music_t* JA_LoadMusic(const char* filename) { inline auto JA_LoadMusic(const char* filename) -> JA_Music_t* {
// Carreguem primer el arxiu en memòria i després el descomprimim. // Carreguem primer el arxiu en memòria i després el descomprimim.
FILE* f = fopen(filename, "rb"); FILE* f = fopen(filename, "rb");
if (!f) return nullptr; if (f == nullptr) {
return nullptr;
}
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
long fsize = ftell(f); long fsize = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
auto* buffer = static_cast<Uint8*>(malloc(fsize + 1)); auto* buffer = static_cast<Uint8*>(malloc(fsize + 1));
if (!buffer) { if (buffer == nullptr) {
fclose(f); fclose(f);
return nullptr; return nullptr;
} }
@@ -313,7 +352,7 @@ inline JA_Music_t* JA_LoadMusic(const char* filename) {
fclose(f); fclose(f);
JA_Music_t* music = JA_LoadMusic(static_cast<const Uint8*>(buffer), static_cast<Uint32>(fsize)); JA_Music_t* music = JA_LoadMusic(static_cast<const Uint8*>(buffer), static_cast<Uint32>(fsize));
if (music) { if (music != nullptr) {
music->filename = filename; music->filename = filename;
} }
@@ -323,7 +362,9 @@ inline JA_Music_t* JA_LoadMusic(const char* filename) {
} }
inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) { inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) {
if (!JA_musicEnabled || !music || !music->vorbis) return; if (!JA_musicEnabled || (music == nullptr) || (music->vorbis == nullptr)) {
return;
}
JA_StopMusic(); JA_StopMusic();
@@ -336,7 +377,7 @@ inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) {
stb_vorbis_seek_start(current_music->vorbis); stb_vorbis_seek_start(current_music->vorbis);
current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec); current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec);
if (!current_music->stream) { if (current_music->stream == nullptr) {
std::cout << "Failed to create audio stream!" << '\n'; std::cout << "Failed to create audio stream!" << '\n';
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
return; return;
@@ -351,23 +392,35 @@ inline void JA_PlayMusic(JA_Music_t* music, const int loop = -1) {
} }
} }
inline const char* JA_GetMusicFilename(const JA_Music_t* music = nullptr) { inline auto JA_GetMusicFilename(const JA_Music_t* music = nullptr) -> const char* {
if (!music) music = current_music; if (music == nullptr) {
if (!music || music->filename.empty()) return nullptr; music = current_music;
}
if ((music == nullptr) || music->filename.empty()) {
return nullptr;
}
return music->filename.c_str(); return music->filename.c_str();
} }
inline void JA_PauseMusic() { inline void JA_PauseMusic() {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) {
if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; return;
}
if ((current_music == nullptr) || current_music->state != JA_MUSIC_PLAYING) {
return;
}
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
SDL_UnbindAudioStream(current_music->stream); SDL_UnbindAudioStream(current_music->stream);
} }
inline void JA_ResumeMusic() { inline void JA_ResumeMusic() {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) {
if (!current_music || current_music->state != JA_MUSIC_PAUSED) return; return;
}
if ((current_music == nullptr) || current_music->state != JA_MUSIC_PAUSED) {
return;
}
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
SDL_BindAudioStream(sdlAudioDevice, current_music->stream); SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
@@ -375,33 +428,39 @@ inline void JA_ResumeMusic() {
inline void JA_StopMusic() { inline void JA_StopMusic() {
// Limpiar outgoing crossfade si existe // Limpiar outgoing crossfade si existe
if (outgoing_music.stream) { if (outgoing_music.stream != nullptr) {
SDL_DestroyAudioStream(outgoing_music.stream); SDL_DestroyAudioStream(outgoing_music.stream);
outgoing_music.stream = nullptr; outgoing_music.stream = nullptr;
outgoing_music.fade.active = false; outgoing_music.fade.active = false;
} }
incoming_fade.active = false; incoming_fade.active = false;
if (!current_music || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) return; if ((current_music == nullptr) || current_music->state == JA_MUSIC_INVALID || current_music->state == JA_MUSIC_STOPPED) {
return;
}
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
if (current_music->stream) { if (current_music->stream != nullptr) {
SDL_DestroyAudioStream(current_music->stream); SDL_DestroyAudioStream(current_music->stream);
current_music->stream = nullptr; current_music->stream = nullptr;
} }
// Deixem el handle de vorbis viu — es tanca en JA_DeleteMusic. // Deixem el handle de vorbis viu — es tanca en JA_DeleteMusic.
// Rebobinem perquè un futur JA_PlayMusic comence des del principi. // Rebobinem perquè un futur JA_PlayMusic comence des del principi.
if (current_music->vorbis) { if (current_music->vorbis != nullptr) {
stb_vorbis_seek_start(current_music->vorbis); stb_vorbis_seek_start(current_music->vorbis);
} }
} }
inline void JA_FadeOutMusic(const int milliseconds) { inline void JA_FadeOutMusic(const int milliseconds) {
if (!JA_musicEnabled) return; if (!JA_musicEnabled) {
if (!current_music || current_music->state != JA_MUSIC_PLAYING) return; return;
}
if ((current_music == nullptr) || current_music->state != JA_MUSIC_PLAYING) {
return;
}
// Destruir outgoing anterior si existe // Destruir outgoing anterior si existe
if (outgoing_music.stream) { if (outgoing_music.stream != nullptr) {
SDL_DestroyAudioStream(outgoing_music.stream); SDL_DestroyAudioStream(outgoing_music.stream);
outgoing_music.stream = nullptr; outgoing_music.stream = nullptr;
} }
@@ -412,20 +471,24 @@ inline void JA_FadeOutMusic(const int milliseconds) {
// Robar el stream del current_music al outgoing // Robar el stream del current_music al outgoing
outgoing_music.stream = current_music->stream; outgoing_music.stream = current_music->stream;
outgoing_music.fade = {true, SDL_GetTicks(), milliseconds, JA_musicVolume}; outgoing_music.fade = {.active = true, .start_time = SDL_GetTicks(), .duration_ms = milliseconds, .initial_volume = JA_musicVolume};
// Dejar current_music sin stream (ya lo tiene outgoing) // Dejar current_music sin stream (ya lo tiene outgoing)
current_music->stream = nullptr; current_music->stream = nullptr;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis); if (current_music->vorbis != nullptr) {
stb_vorbis_seek_start(current_music->vorbis);
}
incoming_fade.active = false; incoming_fade.active = false;
} }
inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const int loop) { inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const int loop) {
if (!JA_musicEnabled || !music || !music->vorbis) return; if (!JA_musicEnabled || (music == nullptr) || (music->vorbis == nullptr)) {
return;
}
// Destruir outgoing anterior si existe (crossfade durante crossfade) // Destruir outgoing anterior si existe (crossfade durante crossfade)
if (outgoing_music.stream) { if (outgoing_music.stream != nullptr) {
SDL_DestroyAudioStream(outgoing_music.stream); SDL_DestroyAudioStream(outgoing_music.stream);
outgoing_music.stream = nullptr; outgoing_music.stream = nullptr;
outgoing_music.fade.active = false; outgoing_music.fade.active = false;
@@ -434,13 +497,15 @@ inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const i
// Robar el stream de la musica actual al outgoing para el fade-out. // Robar el stream de la musica actual al outgoing para el fade-out.
// Pre-omplim amb `crossfade_ms` de so perquè no es quede en silenci // Pre-omplim amb `crossfade_ms` de so perquè no es quede en silenci
// abans d'acabar el fade (l'stream robat ja no pot alimentar-se). // abans d'acabar el fade (l'stream robat ja no pot alimentar-se).
if (current_music && current_music->state == JA_MUSIC_PLAYING && current_music->stream) { if ((current_music != nullptr) && current_music->state == JA_MUSIC_PLAYING && (current_music->stream != nullptr)) {
JA_PreFillOutgoing(current_music, crossfade_ms); JA_PreFillOutgoing(current_music, crossfade_ms);
outgoing_music.stream = current_music->stream; outgoing_music.stream = current_music->stream;
outgoing_music.fade = {true, SDL_GetTicks(), crossfade_ms, JA_musicVolume}; outgoing_music.fade = {.active = true, .start_time = SDL_GetTicks(), .duration_ms = crossfade_ms, .initial_volume = JA_musicVolume};
current_music->stream = nullptr; current_music->stream = nullptr;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
if (current_music->vorbis) stb_vorbis_seek_start(current_music->vorbis); if (current_music->vorbis != nullptr) {
stb_vorbis_seek_start(current_music->vorbis);
}
} }
// Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente) // Iniciar la nueva pista con gain=0 (el fade-in la sube gradualmente)
@@ -450,42 +515,52 @@ inline void JA_CrossfadeMusic(JA_Music_t* music, const int crossfade_ms, const i
stb_vorbis_seek_start(current_music->vorbis); stb_vorbis_seek_start(current_music->vorbis);
current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec); current_music->stream = SDL_CreateAudioStream(&current_music->spec, &JA_audioSpec);
if (!current_music->stream) { if (current_music->stream == nullptr) {
std::cout << "Failed to create audio stream for crossfade!" << '\n'; std::cout << "Failed to create audio stream for crossfade!" << '\n';
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
return; return;
} }
SDL_SetAudioStreamGain(current_music->stream, 0.0f); SDL_SetAudioStreamGain(current_music->stream, 0.0F);
JA_PumpMusic(current_music); // pre-carrega abans de bindejar JA_PumpMusic(current_music); // pre-carrega abans de bindejar
SDL_BindAudioStream(sdlAudioDevice, current_music->stream); SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
// Configurar fade-in // Configurar fade-in
incoming_fade = {true, SDL_GetTicks(), crossfade_ms, 0.0f}; incoming_fade = {.active = true, .start_time = SDL_GetTicks(), .duration_ms = crossfade_ms, .initial_volume = 0.0F};
} }
inline JA_Music_state JA_GetMusicState() { inline auto JA_GetMusicState() -> JA_Music_state {
if (!JA_musicEnabled) return JA_MUSIC_DISABLED; if (!JA_musicEnabled) {
if (!current_music) return JA_MUSIC_INVALID; return JA_MUSIC_DISABLED;
}
if (current_music == nullptr) {
return JA_MUSIC_INVALID;
}
return current_music->state; return current_music->state;
} }
inline void JA_DeleteMusic(JA_Music_t* music) { inline void JA_DeleteMusic(JA_Music_t* music) {
if (!music) return; if (music == nullptr) {
return;
}
if (current_music == music) { if (current_music == music) {
JA_StopMusic(); JA_StopMusic();
current_music = nullptr; current_music = nullptr;
} }
if (music->stream) SDL_DestroyAudioStream(music->stream); if (music->stream != nullptr) {
if (music->vorbis) stb_vorbis_close(music->vorbis); SDL_DestroyAudioStream(music->stream);
}
if (music->vorbis != nullptr) {
stb_vorbis_close(music->vorbis);
}
// ogg_data (std::vector) i filename (std::string) s'alliberen sols // ogg_data (std::vector) i filename (std::string) s'alliberen sols
// al destructor de JA_Music_t. // al destructor de JA_Music_t.
delete music; delete music;
} }
inline float JA_SetMusicVolume(float volume) { inline auto JA_SetMusicVolume(float volume) -> float {
JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f); JA_musicVolume = SDL_clamp(volume, 0.0F, 1.0F);
if (current_music && current_music->stream) { if ((current_music != nullptr) && (current_music->stream != nullptr)) {
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
} }
return JA_musicVolume; return JA_musicVolume;
@@ -495,18 +570,20 @@ inline void JA_SetMusicPosition(float /*value*/) {
// No implementat amb el backend de streaming. // No implementat amb el backend de streaming.
} }
inline float JA_GetMusicPosition() { inline auto JA_GetMusicPosition() -> float {
return 0.0f; return 0.0F;
} }
inline void JA_EnableMusic(const bool value) { inline void JA_EnableMusic(const bool value) {
if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) JA_StopMusic(); if (!value && (current_music != nullptr) && (current_music->state == JA_MUSIC_PLAYING)) {
JA_StopMusic();
}
JA_musicEnabled = value; JA_musicEnabled = value;
} }
// --- Sound Functions --- // --- Sound Functions ---
inline JA_Sound_t* JA_LoadSound(uint8_t* buffer, uint32_t size) { inline auto JA_LoadSound(uint8_t* buffer, uint32_t size) -> JA_Sound_t* {
auto sound = std::make_unique<JA_Sound_t>(); auto sound = std::make_unique<JA_Sound_t>();
Uint8* raw = nullptr; Uint8* raw = nullptr;
if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) { if (!SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &raw, &sound->length)) {
@@ -517,7 +594,7 @@ inline JA_Sound_t* JA_LoadSound(uint8_t* buffer, uint32_t size) {
return sound.release(); return sound.release();
} }
inline JA_Sound_t* JA_LoadSound(const char* filename) { inline auto JA_LoadSound(const char* filename) -> JA_Sound_t* {
auto sound = std::make_unique<JA_Sound_t>(); auto sound = std::make_unique<JA_Sound_t>();
Uint8* raw = nullptr; Uint8* raw = nullptr;
if (!SDL_LoadWAV(filename, &sound->spec, &raw, &sound->length)) { if (!SDL_LoadWAV(filename, &sound->spec, &raw, &sound->length)) {
@@ -528,8 +605,10 @@ inline JA_Sound_t* JA_LoadSound(const char* filename) {
return sound.release(); return sound.release();
} }
inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) { inline auto JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group = 0) -> int {
if (!JA_soundEnabled || !sound) return -1; if (!JA_soundEnabled || (sound == nullptr)) {
return -1;
}
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
@@ -541,9 +620,13 @@ inline int JA_PlaySound(JA_Sound_t* sound, const int loop = 0, const int group =
return JA_PlaySoundOnChannel(sound, channel, loop, group); return JA_PlaySoundOnChannel(sound, channel, loop, group);
} }
inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop, const int group) { inline auto JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop, const int group) -> int {
if (!JA_soundEnabled || !sound) return -1; if (!JA_soundEnabled || (sound == nullptr)) {
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; return -1;
}
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) {
return -1;
}
JA_StopChannel(channel); JA_StopChannel(channel);
@@ -554,7 +637,7 @@ inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int
channels[channel].state = JA_CHANNEL_PLAYING; channels[channel].state = JA_CHANNEL_PLAYING;
channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec); channels[channel].stream = SDL_CreateAudioStream(&channels[channel].sound->spec, &JA_audioSpec);
if (!channels[channel].stream) { if (channels[channel].stream == nullptr) {
std::cout << "Failed to create audio stream for sound!" << '\n'; std::cout << "Failed to create audio stream for sound!" << '\n';
channels[channel].state = JA_CHANNEL_FREE; channels[channel].state = JA_CHANNEL_FREE;
return -1; return -1;
@@ -568,22 +651,29 @@ inline int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int
} }
inline void JA_DeleteSound(JA_Sound_t* sound) { inline void JA_DeleteSound(JA_Sound_t* sound) {
if (!sound) return; if (sound == nullptr) {
return;
}
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
if (channels[i].sound == sound) JA_StopChannel(i); if (channels[i].sound == sound) {
JA_StopChannel(i);
}
} }
// buffer es destrueix automàticament via RAII (SDLFreeDeleter). // buffer es destrueix automàticament via RAII (SDLFreeDeleter).
delete sound; delete sound;
} }
inline void JA_PauseChannel(const int channel) { inline void JA_PauseChannel(const int channel) {
if (!JA_soundEnabled) return; if (!JA_soundEnabled) {
return;
}
if (channel == -1) { if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (auto& channel : channels) {
if (channels[i].state == JA_CHANNEL_PLAYING) { if (channel.state == JA_CHANNEL_PLAYING) {
channels[i].state = JA_CHANNEL_PAUSED; channel.state = JA_CHANNEL_PAUSED;
SDL_UnbindAudioStream(channels[i].stream); SDL_UnbindAudioStream(channel.stream);
}
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PLAYING) { if (channels[channel].state == JA_CHANNEL_PLAYING) {
@@ -594,13 +684,16 @@ inline void JA_PauseChannel(const int channel) {
} }
inline void JA_ResumeChannel(const int channel) { inline void JA_ResumeChannel(const int channel) {
if (!JA_soundEnabled) return; if (!JA_soundEnabled) {
return;
}
if (channel == -1) { if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (auto& channel : channels) {
if (channels[i].state == JA_CHANNEL_PAUSED) { if (channel.state == JA_CHANNEL_PAUSED) {
channels[i].state = JA_CHANNEL_PLAYING; channel.state = JA_CHANNEL_PLAYING;
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); SDL_BindAudioStream(sdlAudioDevice, channel.stream);
}
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state == JA_CHANNEL_PAUSED) { if (channels[channel].state == JA_CHANNEL_PAUSED) {
@@ -612,18 +705,22 @@ inline void JA_ResumeChannel(const int channel) {
inline void JA_StopChannel(const int channel) { inline void JA_StopChannel(const int channel) {
if (channel == -1) { if (channel == -1) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { for (auto& channel : channels) {
if (channels[i].state != JA_CHANNEL_FREE) { if (channel.state != JA_CHANNEL_FREE) {
if (channels[i].stream) SDL_DestroyAudioStream(channels[i].stream); if (channel.stream != nullptr) {
channels[i].stream = nullptr; SDL_DestroyAudioStream(channel.stream);
channels[i].state = JA_CHANNEL_FREE; }
channels[i].pos = 0; channel.stream = nullptr;
channels[i].sound = nullptr; channel.state = JA_CHANNEL_FREE;
channel.pos = 0;
channel.sound = nullptr;
} }
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
if (channels[channel].state != JA_CHANNEL_FREE) { if (channels[channel].state != JA_CHANNEL_FREE) {
if (channels[channel].stream) SDL_DestroyAudioStream(channels[channel].stream); if (channels[channel].stream != nullptr) {
SDL_DestroyAudioStream(channels[channel].stream);
}
channels[channel].stream = nullptr; channels[channel].stream = nullptr;
channels[channel].state = JA_CHANNEL_FREE; channels[channel].state = JA_CHANNEL_FREE;
channels[channel].pos = 0; channels[channel].pos = 0;
@@ -632,19 +729,23 @@ inline void JA_StopChannel(const int channel) {
} }
} }
inline JA_Channel_state JA_GetChannelState(const int channel) { inline auto JA_GetChannelState(const int channel) -> JA_Channel_state {
if (!JA_soundEnabled) return JA_SOUND_DISABLED; if (!JA_soundEnabled) {
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; return JA_SOUND_DISABLED;
}
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) {
return JA_CHANNEL_INVALID;
}
return channels[channel].state; return channels[channel].state;
} }
inline float JA_SetSoundVolume(float volume, const int group = -1) { inline auto JA_SetSoundVolume(float volume, const int group = -1) -> float {
const float v = SDL_clamp(volume, 0.0f, 1.0f); const float v = SDL_clamp(volume, 0.0F, 1.0F);
if (group == -1) { if (group == -1) {
for (int i = 0; i < JA_MAX_GROUPS; ++i) { for (float& i : JA_soundVolume) {
JA_soundVolume[i] = v; i = v;
} }
} else if (group >= 0 && group < JA_MAX_GROUPS) { } else if (group >= 0 && group < JA_MAX_GROUPS) {
JA_soundVolume[group] = v; JA_soundVolume[group] = v;
@@ -653,11 +754,11 @@ inline float JA_SetSoundVolume(float volume, const int group = -1) {
} }
// Aplicar volum als canals actius. // Aplicar volum als canals actius.
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { for (auto& channel : channels) {
if ((channels[i].state == JA_CHANNEL_PLAYING) || (channels[i].state == JA_CHANNEL_PAUSED)) { if ((channel.state == JA_CHANNEL_PLAYING) || (channel.state == JA_CHANNEL_PAUSED)) {
if (group == -1 || channels[i].group == group) { if (group == -1 || channel.group == group) {
if (channels[i].stream) { if (channel.stream != nullptr) {
SDL_SetAudioStreamGain(channels[i].stream, JA_soundVolume[channels[i].group]); SDL_SetAudioStreamGain(channel.stream, JA_soundVolume[channel.group]);
} }
} }
} }
@@ -672,7 +773,7 @@ inline void JA_EnableSound(const bool value) {
JA_soundEnabled = value; JA_soundEnabled = value;
} }
inline float JA_SetVolume(float volume) { inline auto JA_SetVolume(float volume) -> float {
float v = JA_SetMusicVolume(volume); float v = JA_SetMusicVolume(volume);
JA_SetSoundVolume(v, -1); JA_SetSoundVolume(v, -1);
return v; return v;
+38 -49
View File
@@ -4,6 +4,7 @@
#include <algorithm> // for any_of #include <algorithm> // for any_of
#include <iostream> // for basic_ostream, operator<<, cout, basi... #include <iostream> // for basic_ostream, operator<<, cout, basi...
#include <utility>
// Emscripten-only: SDL 3.4+ ja no casa el GUID dels mandos de Chrome Android // Emscripten-only: SDL 3.4+ ja no casa el GUID dels mandos de Chrome Android
// amb gamecontrollerdb (el gamepad.id d'Android no porta Vendor/Product, el // amb gamecontrollerdb (el gamepad.id d'Android no porta Vendor/Product, el
@@ -58,12 +59,8 @@ auto Input::get() -> Input * {
} }
// Constructor // Constructor
Input::Input(const std::string &file) Input::Input(std::string file)
: numGamepads(0), : dbPath(std::move(file)) {
dbPath(file),
verbose(true),
disabledUntil(d_notDisabled),
enabled(true) {
// Inicializa las variables // Inicializa las variables
keyBindings_t kb; keyBindings_t kb;
kb.scancode = 0; kb.scancode = 0;
@@ -107,7 +104,7 @@ void Input::bindGameControllerButton(Uint8 input, SDL_GamepadButton button) {
} }
// Comprueba si un input esta activo // Comprueba si un input esta activo
bool Input::checkInput(Uint8 input, bool repeat, int device, int index) { auto Input::checkInput(Uint8 input, bool repeat, int device, int index) -> bool {
if (!enabled) { if (!enabled) {
return false; return false;
} }
@@ -123,11 +120,7 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) {
const bool *keyStates = SDL_GetKeyboardState(nullptr); const bool *keyStates = SDL_GetKeyboardState(nullptr);
if (repeat) { if (repeat) {
if (keyStates[keyBindings[input].scancode]) { successKeyboard = keyStates[keyBindings[input].scancode];
successKeyboard = true;
} else {
successKeyboard = false;
}
} else { } else {
if (!keyBindings[input].active) { if (!keyBindings[input].active) {
if (keyStates[keyBindings[input].scancode]) { if (keyStates[keyBindings[input].scancode]) {
@@ -147,14 +140,10 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) {
} }
} }
if (gameControllerFound() && index >= 0 && index < (int)connectedControllers.size()) if (gameControllerFound() && index >= 0 && index < (int)connectedControllers.size()) {
if ((device == INPUT_USE_GAMECONTROLLER) || (device == INPUT_USE_ANY)) { if ((device == INPUT_USE_GAMECONTROLLER) || (device == INPUT_USE_ANY)) {
if (repeat) { if (repeat) {
if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button)) { successGameController = SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button);
successGameController = true;
} else {
successGameController = false;
}
} else { } else {
if (!gameControllerBindings[input].active) { if (!gameControllerBindings[input].active) {
if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button)) { if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[input].button)) {
@@ -173,12 +162,13 @@ bool Input::checkInput(Uint8 input, bool repeat, int device, int index) {
} }
} }
} }
}
return (successKeyboard || successGameController); return (successKeyboard || successGameController);
} }
// Comprueba si hay almenos un input activo // Comprueba si hay almenos un input activo
bool Input::checkAnyInput(int device, int index) { auto Input::checkAnyInput(int device, int index) -> bool {
if (device == INPUT_USE_ANY) { if (device == INPUT_USE_ANY) {
index = 0; index = 0;
} }
@@ -186,8 +176,8 @@ bool Input::checkAnyInput(int device, int index) {
if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY) { if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY) {
const bool *mKeystates = SDL_GetKeyboardState(nullptr); const bool *mKeystates = SDL_GetKeyboardState(nullptr);
for (int i = 0; i < (int)keyBindings.size(); ++i) { for (auto &keyBinding : keyBindings) {
if (mKeystates[keyBindings[i].scancode]) { if (mKeystates[keyBinding.scancode]) {
return true; return true;
} }
} }
@@ -195,8 +185,8 @@ bool Input::checkAnyInput(int device, int index) {
if (gameControllerFound() && index >= 0 && index < (int)connectedControllers.size()) { if (gameControllerFound() && index >= 0 && index < (int)connectedControllers.size()) {
if (device == INPUT_USE_GAMECONTROLLER || device == INPUT_USE_ANY) { if (device == INPUT_USE_GAMECONTROLLER || device == INPUT_USE_ANY) {
for (int i = 0; i < (int)gameControllerBindings.size(); ++i) { for (auto &gameControllerBinding : gameControllerBindings) {
if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBindings[i].button)) { if (SDL_GetGamepadButton(connectedControllers[index], gameControllerBinding.button)) {
return true; return true;
} }
} }
@@ -209,10 +199,10 @@ bool Input::checkAnyInput(int device, int index) {
// Construye el nombre visible de un mando. // Construye el nombre visible de un mando.
// Recorta des del primer '(' o '[' (per a evitar coses tipus // Recorta des del primer '(' o '[' (per a evitar coses tipus
// "Retroid Controller (vendor: 1001) ...") i talla a 25 caràcters. // "Retroid Controller (vendor: 1001) ...") i talla a 25 caràcters.
std::string Input::buildControllerName(SDL_Gamepad *pad, int padIndex) { auto Input::buildControllerName(SDL_Gamepad *pad, int padIndex) -> std::string {
(void)padIndex; (void)padIndex;
const char *padName = SDL_GetGamepadName(pad); const char *padName = SDL_GetGamepadName(pad);
std::string name = padName ? padName : "Unknown"; std::string name = (padName != nullptr) ? padName : "Unknown";
const auto pos = name.find_first_of("(["); const auto pos = name.find_first_of("([");
if (pos != std::string::npos) { if (pos != std::string::npos) {
name.erase(pos); name.erase(pos);
@@ -228,7 +218,7 @@ std::string Input::buildControllerName(SDL_Gamepad *pad, int padIndex) {
// Busca si hay un mando conectado. Cierra y limpia el estado previo para // Busca si hay un mando conectado. Cierra y limpia el estado previo para
// que la función sea idempotente si se invoca más de una vez. // que la función sea idempotente si se invoca más de una vez.
bool Input::discoverGameController() { auto Input::discoverGameController() -> bool {
// Cierra los mandos ya abiertos y limpia los vectores paralelos // Cierra los mandos ya abiertos y limpia los vectores paralelos
for (auto *pad : connectedControllers) { for (auto *pad : connectedControllers) {
if (pad != nullptr) { if (pad != nullptr) {
@@ -248,14 +238,14 @@ bool Input::discoverGameController() {
if (SDL_AddGamepadMappingsFromFile(dbPath.c_str()) < 0) { if (SDL_AddGamepadMappingsFromFile(dbPath.c_str()) < 0) {
if (verbose) { if (verbose) {
std::cout << "Error, could not load " << dbPath.c_str() << " file: " << SDL_GetError() << std::endl; std::cout << "Error, could not load " << dbPath.c_str() << " file: " << SDL_GetError() << '\n';
} }
} }
int nJoysticks = 0; int nJoysticks = 0;
SDL_JoystickID *joysticks = SDL_GetJoysticks(&nJoysticks); SDL_JoystickID *joysticks = SDL_GetJoysticks(&nJoysticks);
if (joysticks) { if (joysticks != nullptr) {
int gamepadCount = 0; int gamepadCount = 0;
for (int i = 0; i < nJoysticks; ++i) { for (int i = 0; i < nJoysticks; ++i) {
if (SDL_IsGamepad(joysticks[i])) { if (SDL_IsGamepad(joysticks[i])) {
@@ -273,7 +263,9 @@ bool Input::discoverGameController() {
int padIndex = 0; int padIndex = 0;
for (int i = 0; i < nJoysticks; i++) { for (int i = 0; i < nJoysticks; i++) {
if (!SDL_IsGamepad(joysticks[i])) continue; if (!SDL_IsGamepad(joysticks[i])) {
continue;
}
installWebStandardMapping(joysticks[i]); installWebStandardMapping(joysticks[i]);
SDL_Gamepad *pad = SDL_OpenGamepad(joysticks[i]); SDL_Gamepad *pad = SDL_OpenGamepad(joysticks[i]);
@@ -285,11 +277,11 @@ bool Input::discoverGameController() {
numGamepads++; numGamepads++;
padIndex++; padIndex++;
if (verbose) { if (verbose) {
std::cout << name << std::endl; std::cout << name << '\n';
} }
} else { } else {
if (verbose) { if (verbose) {
std::cout << "SDL_GetError() = " << SDL_GetError() << std::endl; std::cout << "SDL_GetError() = " << SDL_GetError() << '\n';
} }
} }
} }
@@ -304,13 +296,13 @@ bool Input::discoverGameController() {
} }
// Procesa un evento SDL_EVENT_GAMEPAD_ADDED // Procesa un evento SDL_EVENT_GAMEPAD_ADDED
bool Input::handleGamepadAdded(SDL_JoystickID jid, std::string &outName) { auto Input::handleGamepadAdded(SDL_JoystickID jid, std::string &outName) -> bool {
if (!SDL_IsGamepad(jid)) { if (!SDL_IsGamepad(jid)) {
return false; return false;
} }
// Si el mando ya está registrado no hace nada (ej. evento retroactivo tras el scan inicial) // Si el mando ya está registrado no hace nada (ej. evento retroactivo tras el scan inicial)
if (std::any_of(connectedControllerIds.begin(), connectedControllerIds.end(), [jid](SDL_JoystickID existing) { return existing == jid; })) { if (std::ranges::any_of(connectedControllerIds, [jid](SDL_JoystickID existing) { return existing == jid; })) {
return false; return false;
} }
@@ -318,7 +310,7 @@ bool Input::handleGamepadAdded(SDL_JoystickID jid, std::string &outName) {
SDL_Gamepad *pad = SDL_OpenGamepad(jid); SDL_Gamepad *pad = SDL_OpenGamepad(jid);
if (pad == nullptr) { if (pad == nullptr) {
if (verbose) { if (verbose) {
std::cout << "Failed to open gamepad " << jid << ": " << SDL_GetError() << std::endl; std::cout << "Failed to open gamepad " << jid << ": " << SDL_GetError() << '\n';
} }
return false; return false;
} }
@@ -331,7 +323,7 @@ bool Input::handleGamepadAdded(SDL_JoystickID jid, std::string &outName) {
numGamepads++; numGamepads++;
if (verbose) { if (verbose) {
std::cout << "Gamepad connected: " << name << std::endl; std::cout << "Gamepad connected: " << name << '\n';
} }
outName = name; outName = name;
@@ -339,9 +331,11 @@ bool Input::handleGamepadAdded(SDL_JoystickID jid, std::string &outName) {
} }
// Procesa un evento SDL_EVENT_GAMEPAD_REMOVED // Procesa un evento SDL_EVENT_GAMEPAD_REMOVED
bool Input::handleGamepadRemoved(SDL_JoystickID jid, std::string &outName) { auto Input::handleGamepadRemoved(SDL_JoystickID jid, std::string &outName) -> bool {
for (size_t i = 0; i < connectedControllerIds.size(); ++i) { for (size_t i = 0; i < connectedControllerIds.size(); ++i) {
if (connectedControllerIds[i] != jid) continue; if (connectedControllerIds[i] != jid) {
continue;
}
outName = controllerNames[i]; outName = controllerNames[i];
if (connectedControllers[i] != nullptr) { if (connectedControllers[i] != nullptr) {
@@ -351,10 +345,10 @@ bool Input::handleGamepadRemoved(SDL_JoystickID jid, std::string &outName) {
connectedControllerIds.erase(connectedControllerIds.begin() + i); connectedControllerIds.erase(connectedControllerIds.begin() + i);
controllerNames.erase(controllerNames.begin() + i); controllerNames.erase(controllerNames.begin() + i);
numGamepads--; numGamepads--;
if (numGamepads < 0) numGamepads = 0; numGamepads = std::max(numGamepads, 0);
if (verbose) { if (verbose) {
std::cout << "Gamepad disconnected: " << outName << std::endl; std::cout << "Gamepad disconnected: " << outName << '\n';
} }
return true; return true;
@@ -363,25 +357,20 @@ bool Input::handleGamepadRemoved(SDL_JoystickID jid, std::string &outName) {
} }
// Comprueba si hay algun mando conectado // Comprueba si hay algun mando conectado
bool Input::gameControllerFound() { auto Input::gameControllerFound() const -> bool {
if (numGamepads > 0) { return numGamepads > 0;
return true;
} else {
return false;
}
} }
// Obten el nombre de un mando de juego // Obten el nombre de un mando de juego
std::string Input::getControllerName(int index) { auto Input::getControllerName(int index) -> std::string {
if (numGamepads > 0) { if (numGamepads > 0) {
return controllerNames[index]; return controllerNames[index];
} else {
return "";
} }
return "";
} }
// Obten el numero de mandos conectados // Obten el numero de mandos conectados
int Input::getNumControllers() { auto Input::getNumControllers() const -> int {
return numGamepads; return numGamepads;
} }
+17 -16
View File
@@ -2,6 +2,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <cstdint> // for uint8_t
#include <string> // for string, basic_string #include <string> // for string, basic_string
#include <vector> // for vector #include <vector> // for vector
@@ -14,7 +15,7 @@ constexpr int INPUT_USE_KEYBOARD = 0;
constexpr int INPUT_USE_GAMECONTROLLER = 1; constexpr int INPUT_USE_GAMECONTROLLER = 1;
constexpr int INPUT_USE_ANY = 2; constexpr int INPUT_USE_ANY = 2;
enum inputs_e { enum inputs_e : std::uint8_t {
// Inputs obligatorios // Inputs obligatorios
input_null, input_null,
input_up, input_up,
@@ -43,7 +44,7 @@ enum inputs_e {
input_number_of_inputs input_number_of_inputs
}; };
enum i_disable_e { enum i_disable_e : std::uint8_t {
d_notDisabled, d_notDisabled,
d_forever, d_forever,
d_keyPressed d_keyPressed
@@ -69,17 +70,17 @@ class Input {
std::vector<keyBindings_t> keyBindings; // Vector con las teclas asociadas a los inputs predefinidos std::vector<keyBindings_t> keyBindings; // Vector con las teclas asociadas a los inputs predefinidos
std::vector<GameControllerBindings_t> gameControllerBindings; // Vector con las teclas asociadas a los inputs predefinidos std::vector<GameControllerBindings_t> gameControllerBindings; // Vector con las teclas asociadas a los inputs predefinidos
std::vector<std::string> controllerNames; // Vector con los nombres de los mandos std::vector<std::string> controllerNames; // Vector con los nombres de los mandos
int numGamepads; // Numero de mandos conectados int numGamepads{0}; // Numero de mandos conectados
std::string dbPath; // Ruta al archivo gamecontrollerdb.txt std::string dbPath; // Ruta al archivo gamecontrollerdb.txt
bool verbose; // Indica si ha de mostrar mensajes bool verbose{true}; // Indica si ha de mostrar mensajes
i_disable_e disabledUntil; // Tiempo que esta deshabilitado i_disable_e disabledUntil{d_notDisabled}; // Tiempo que esta deshabilitado
bool enabled; // Indica si está habilitado bool enabled{true}; // Indica si está habilitado
// Construye el nombre visible de un mando (name truncado + sufijo #N) // Construye el nombre visible de un mando (name truncado + sufijo #N)
std::string buildControllerName(SDL_Gamepad *pad, int padIndex); static auto buildControllerName(SDL_Gamepad *pad, int padIndex) -> std::string;
// Constructor privado (usar Input::init) // Constructor privado (usar Input::init)
explicit Input(const std::string &file); explicit Input(std::string file);
// Instancia única // Instancia única
static Input *instance; static Input *instance;
@@ -103,30 +104,30 @@ class Input {
void bindGameControllerButton(Uint8 input, SDL_GamepadButton button); void bindGameControllerButton(Uint8 input, SDL_GamepadButton button);
// Comprueba si un input esta activo // Comprueba si un input esta activo
bool checkInput(Uint8 input, bool repeat = true, int device = INPUT_USE_ANY, int index = 0); auto checkInput(Uint8 input, bool repeat = true, int device = INPUT_USE_ANY, int index = 0) -> bool;
// Comprueba si hay almenos un input activo // Comprueba si hay almenos un input activo
bool checkAnyInput(int device = INPUT_USE_ANY, int index = 0); auto checkAnyInput(int device = INPUT_USE_ANY, int index = 0) -> bool;
// Busca si hay un mando conectado // Busca si hay un mando conectado
bool discoverGameController(); auto discoverGameController() -> bool;
// Procesa un evento SDL_EVENT_GAMEPAD_ADDED. Devuelve true si el mando se ha añadido // Procesa un evento SDL_EVENT_GAMEPAD_ADDED. Devuelve true si el mando se ha añadido
// (no estaba ya registrado) y escribe el nombre visible en outName. // (no estaba ya registrado) y escribe el nombre visible en outName.
bool handleGamepadAdded(SDL_JoystickID jid, std::string &outName); auto handleGamepadAdded(SDL_JoystickID jid, std::string &outName) -> bool;
// Procesa un evento SDL_EVENT_GAMEPAD_REMOVED. Devuelve true si se ha encontrado y // Procesa un evento SDL_EVENT_GAMEPAD_REMOVED. Devuelve true si se ha encontrado y
// eliminado, y escribe el nombre visible en outName. // eliminado, y escribe el nombre visible en outName.
bool handleGamepadRemoved(SDL_JoystickID jid, std::string &outName); auto handleGamepadRemoved(SDL_JoystickID jid, std::string &outName) -> bool;
// Comprueba si hay algun mando conectado // Comprueba si hay algun mando conectado
bool gameControllerFound(); [[nodiscard]] auto gameControllerFound() const -> bool;
// Obten el numero de mandos conectados // Obten el numero de mandos conectados
int getNumControllers(); [[nodiscard]] auto getNumControllers() const -> int;
// Obten el nombre de un mando de juego // Obten el nombre de un mando de juego
std::string getControllerName(int index); auto getControllerName(int index) -> std::string;
// Establece si ha de mostrar mensajes // Establece si ha de mostrar mensajes
void setVerbose(bool value); void setVerbose(bool value);
+7 -8
View File
@@ -24,15 +24,13 @@ auto Lang::get() -> Lang * {
} }
// Constructor // Constructor
Lang::Lang() { Lang::Lang() = default;
}
// Destructor // Destructor
Lang::~Lang() { Lang::~Lang() = default;
}
// Inicializa los textos del juego en el idioma seleccionado // Inicializa los textos del juego en el idioma seleccionado
bool Lang::setLang(Uint8 lang) { auto Lang::setLang(Uint8 lang) -> bool {
std::string file; std::string file;
switch (lang) { switch (lang) {
@@ -53,8 +51,9 @@ bool Lang::setLang(Uint8 lang) {
break; break;
} }
for (int i = 0; i < MAX_TEXT_STRINGS; i++) for (auto &mTextString : mTextStrings) {
mTextStrings[i] = ""; mTextString = "";
}
// Lee el fichero via ResourceHelper (pack o filesystem) // Lee el fichero via ResourceHelper (pack o filesystem)
auto bytes = ResourceHelper::loadFile(file); auto bytes = ResourceHelper::loadFile(file);
@@ -90,6 +89,6 @@ bool Lang::setLang(Uint8 lang) {
} }
// Obtiene la cadena de texto del indice // Obtiene la cadena de texto del indice
std::string Lang::getText(int index) { auto Lang::getText(int index) -> std::string {
return mTextStrings[index]; return mTextStrings[index];
} }
+2 -2
View File
@@ -34,8 +34,8 @@ class Lang {
~Lang(); ~Lang();
// Inicializa los textos del juego en el idioma seleccionado // Inicializa los textos del juego en el idioma seleccionado
bool setLang(Uint8 lang); auto setLang(Uint8 lang) -> bool;
// Obtiene la cadena de texto del indice // Obtiene la cadena de texto del indice
std::string getText(int index); auto getText(int index) -> std::string;
}; };
+31 -27
View File
@@ -7,7 +7,7 @@
#include "core/rendering/texture.h" // for Texture #include "core/rendering/texture.h" // for Texture
// Parser compartido: lee un istream con el formato .ani // Parser compartido: lee un istream con el formato .ani
static animatedSprite_t parseAnimationStream(std::istream &file, Texture *texture, const std::string &filename, bool verbose) { static auto parseAnimationStream(std::istream &file, Texture *texture, const std::string &filename, bool verbose) -> animatedSprite_t {
animatedSprite_t as; animatedSprite_t as;
as.texture = texture; as.texture = texture;
int framesPerRow = 0; int framesPerRow = 0;
@@ -17,13 +17,15 @@ static animatedSprite_t parseAnimationStream(std::istream &file, Texture *textur
std::string line; std::string line;
if (verbose) { if (verbose) {
std::cout << "Animation loaded: " << filename << std::endl; std::cout << "Animation loaded: " << filename << '\n';
} }
// Normalitza CRLF: fitxers .ani amb terminadors de Windows fan que // Normalitza CRLF: fitxers .ani amb terminadors de Windows fan que
// line == "[animation]" no faci match i el parser entri en bucle // line == "[animation]" no faci match i el parser entri en bucle
// infinit / no carregui cap animació. // infinit / no carregui cap animació.
auto strip_cr = [](std::string &s) { auto strip_cr = [](std::string &s) {
if (!s.empty() && s.back() == '\r') s.pop_back(); if (!s.empty() && s.back() == '\r') {
s.pop_back();
}
}; };
while (std::getline(file, line)) { while (std::getline(file, line)) {
@@ -37,10 +39,12 @@ static animatedSprite_t parseAnimationStream(std::istream &file, Texture *textur
buffer.completed = false; buffer.completed = false;
do { do {
if (!std::getline(file, line)) break; if (!std::getline(file, line)) {
break;
}
strip_cr(line); strip_cr(line);
int pos = line.find("="); int pos = line.find('=');
if (pos != (int)line.npos) { if (pos != (int)std::string::npos) {
if (line.substr(0, pos) == "name") { if (line.substr(0, pos) == "name") {
buffer.name = line.substr(pos + 1, line.length()); buffer.name = line.substr(pos + 1, line.length());
} else if (line.substr(0, pos) == "speed") { } else if (line.substr(0, pos) == "speed") {
@@ -58,15 +62,15 @@ static animatedSprite_t parseAnimationStream(std::istream &file, Texture *textur
buffer.frames.push_back(rect); buffer.frames.push_back(rect);
} }
} else { } else {
std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl; std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << '\n';
} }
} }
} while (line != "[/animation]"); } while (line != "[/animation]");
as.animations.push_back(buffer); as.animations.push_back(buffer);
} else { } else {
int pos = line.find("="); int pos = line.find('=');
if (pos != (int)line.npos) { if (pos != (int)std::string::npos) {
if (line.substr(0, pos) == "framesPerRow") { if (line.substr(0, pos) == "framesPerRow") {
framesPerRow = std::stoi(line.substr(pos + 1, line.length())); framesPerRow = std::stoi(line.substr(pos + 1, line.length()));
} else if (line.substr(0, pos) == "frameWidth") { } else if (line.substr(0, pos) == "frameWidth") {
@@ -74,7 +78,7 @@ static animatedSprite_t parseAnimationStream(std::istream &file, Texture *textur
} else if (line.substr(0, pos) == "frameHeight") { } else if (line.substr(0, pos) == "frameHeight") {
frameHeight = std::stoi(line.substr(pos + 1, line.length())); frameHeight = std::stoi(line.substr(pos + 1, line.length()));
} else { } else {
std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl; std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << '\n';
} }
if (framesPerRow == 0 && frameWidth > 0) { if (framesPerRow == 0 && frameWidth > 0) {
@@ -93,12 +97,12 @@ static animatedSprite_t parseAnimationStream(std::istream &file, Texture *textur
} }
// Carga la animación desde un fichero // Carga la animación desde un fichero
animatedSprite_t loadAnimationFromFile(Texture *texture, const std::string &filePath, bool verbose) { auto loadAnimationFromFile(Texture *texture, const std::string &filePath, bool verbose) -> animatedSprite_t {
const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1); const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1);
std::ifstream file(filePath); std::ifstream file(filePath);
if (!file.good()) { if (!file.good()) {
if (verbose) { if (verbose) {
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl; std::cout << "Warning: Unable to open " << filename.c_str() << " file" << '\n';
} }
animatedSprite_t as; animatedSprite_t as;
as.texture = texture; as.texture = texture;
@@ -108,7 +112,7 @@ animatedSprite_t loadAnimationFromFile(Texture *texture, const std::string &file
} }
// Carga la animación desde bytes en memoria // Carga la animación desde bytes en memoria
animatedSprite_t loadAnimationFromMemory(Texture *texture, const std::vector<uint8_t> &bytes, const std::string &nameForLogs, bool verbose) { auto loadAnimationFromMemory(Texture *texture, const std::vector<uint8_t> &bytes, const std::string &nameForLogs, bool verbose) -> animatedSprite_t {
if (bytes.empty()) { if (bytes.empty()) {
animatedSprite_t as; animatedSprite_t as;
as.texture = texture; as.texture = texture;
@@ -134,7 +138,7 @@ AnimatedSprite::AnimatedSprite(Texture *texture, SDL_Renderer *renderer, const s
animation.insert(animation.end(), as.animations.begin(), as.animations.end()); animation.insert(animation.end(), as.animations.begin(), as.animations.end());
} }
else if (buffer) { else if (buffer != nullptr) {
loadFromVector(buffer); loadFromVector(buffer);
} }
} }
@@ -159,7 +163,7 @@ AnimatedSprite::~AnimatedSprite() {
} }
// Obtiene el indice de la animación a partir del nombre // Obtiene el indice de la animación a partir del nombre
int AnimatedSprite::getIndex(const std::string &name) { auto AnimatedSprite::getIndex(const std::string &name) -> int {
int index = -1; int index = -1;
for (const auto &a : animation) { for (const auto &a : animation) {
@@ -169,7 +173,7 @@ int AnimatedSprite::getIndex(const std::string &name) {
} }
} }
std::cout << "** Warning: could not find \"" << name.c_str() << "\" animation" << std::endl; std::cout << "** Warning: could not find \"" << name.c_str() << "\" animation" << '\n';
return -1; return -1;
} }
@@ -205,7 +209,7 @@ void AnimatedSprite::animate() {
} }
// Obtiene el numero de frames de la animación actual // Obtiene el numero de frames de la animación actual
int AnimatedSprite::getNumFrames() { auto AnimatedSprite::getNumFrames() -> int {
return (int)animation[currentAnimation].frames.size(); return (int)animation[currentAnimation].frames.size();
} }
@@ -260,22 +264,22 @@ void AnimatedSprite::setAnimationCompleted(int index, bool value) {
} }
// Comprueba si ha terminado la animación // Comprueba si ha terminado la animación
bool AnimatedSprite::animationIsCompleted() { auto AnimatedSprite::animationIsCompleted() -> bool {
return animation[currentAnimation].completed; return animation[currentAnimation].completed;
} }
// Devuelve el rectangulo de una animación y frame concreto // Devuelve el rectangulo de una animación y frame concreto
SDL_Rect AnimatedSprite::getAnimationClip(const std::string &name, Uint8 index) { auto AnimatedSprite::getAnimationClip(const std::string &name, Uint8 index) -> SDL_Rect {
return animation[getIndex(name)].frames[index]; return animation[getIndex(name)].frames[index];
} }
// Devuelve el rectangulo de una animación y frame concreto // Devuelve el rectangulo de una animación y frame concreto
SDL_Rect AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF) { auto AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF) -> SDL_Rect {
return animation[indexA].frames[indexF]; return animation[indexA].frames[indexF];
} }
// Carga la animación desde un vector // Carga la animación desde un vector
bool AnimatedSprite::loadFromVector(std::vector<std::string> *source) { auto AnimatedSprite::loadFromVector(std::vector<std::string> *source) -> bool {
// Inicializa variables // Inicializa variables
int framesPerRow = 0; int framesPerRow = 0;
int frameWidth = 0; int frameWidth = 0;
@@ -307,10 +311,10 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source) {
line = source->at(index); line = source->at(index);
// Encuentra la posición del caracter '=' // Encuentra la posición del caracter '='
int pos = line.find("="); int pos = line.find('=');
// Procesa las dos subcadenas // Procesa las dos subcadenas
if (pos != (int)line.npos) { if (pos != (int)std::string::npos) {
if (line.substr(0, pos) == "name") { if (line.substr(0, pos) == "name") {
buffer.name = line.substr(pos + 1, line.length()); buffer.name = line.substr(pos + 1, line.length());
} }
@@ -338,7 +342,7 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source) {
} }
else { else {
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl; std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << '\n';
success = false; success = false;
} }
} }
@@ -351,10 +355,10 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source) {
// En caso contrario se parsea el fichero para buscar las variables y los valores // En caso contrario se parsea el fichero para buscar las variables y los valores
else { else {
// Encuentra la posición del caracter '=' // Encuentra la posición del caracter '='
int pos = line.find("="); int pos = line.find('=');
// Procesa las dos subcadenas // Procesa las dos subcadenas
if (pos != (int)line.npos) { if (pos != (int)std::string::npos) {
if (line.substr(0, pos) == "framesPerRow") { if (line.substr(0, pos) == "framesPerRow") {
framesPerRow = std::stoi(line.substr(pos + 1, line.length())); framesPerRow = std::stoi(line.substr(pos + 1, line.length()));
} }
@@ -368,7 +372,7 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source) {
} }
else { else {
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl; std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << '\n';
success = false; success = false;
} }
+8 -8
View File
@@ -25,10 +25,10 @@ struct animatedSprite_t {
}; };
// Carga la animación desde un fichero // Carga la animación desde un fichero
animatedSprite_t loadAnimationFromFile(Texture *texture, const std::string &filePath, bool verbose = false); auto loadAnimationFromFile(Texture *texture, const std::string &filePath, bool verbose = false) -> animatedSprite_t;
// Carga la animación desde bytes en memoria // Carga la animación desde bytes en memoria
animatedSprite_t loadAnimationFromMemory(Texture *texture, const std::vector<uint8_t> &bytes, const std::string &nameForLogs = "", bool verbose = false); auto loadAnimationFromMemory(Texture *texture, const std::vector<uint8_t> &bytes, const std::string &nameForLogs = "", bool verbose = false) -> animatedSprite_t;
class AnimatedSprite : public MovingSprite { class AnimatedSprite : public MovingSprite {
private: private:
@@ -48,7 +48,7 @@ class AnimatedSprite : public MovingSprite {
void animate(); void animate();
// Obtiene el numero de frames de la animación actual // Obtiene el numero de frames de la animación actual
int getNumFrames(); auto getNumFrames() -> int;
// Establece el frame actual de la animación // Establece el frame actual de la animación
void setCurrentFrame(int num); void setCurrentFrame(int num);
@@ -69,17 +69,17 @@ class AnimatedSprite : public MovingSprite {
void setAnimationCompleted(int index, bool value); void setAnimationCompleted(int index, bool value);
// Comprueba si ha terminado la animación // Comprueba si ha terminado la animación
bool animationIsCompleted(); auto animationIsCompleted() -> bool;
// Devuelve el rectangulo de una animación y frame concreto // Devuelve el rectangulo de una animación y frame concreto
SDL_Rect getAnimationClip(const std::string &name = "default", Uint8 index = 0); auto getAnimationClip(const std::string &name = "default", Uint8 index = 0) -> SDL_Rect;
SDL_Rect getAnimationClip(int indexA = 0, Uint8 indexF = 0); auto getAnimationClip(int indexA = 0, Uint8 indexF = 0) -> SDL_Rect;
// Obtiene el indice de la animación a partir del nombre // Obtiene el indice de la animación a partir del nombre
int getIndex(const std::string &name); auto getIndex(const std::string &name) -> int;
// Carga la animación desde un vector // Carga la animación desde un vector
bool loadFromVector(std::vector<std::string> *source); auto loadFromVector(std::vector<std::string> *source) -> bool;
// Establece la animacion actual // Establece la animacion actual
void setCurrentAnimation(const std::string &name = "default"); void setCurrentAnimation(const std::string &name = "default");
+8 -6
View File
@@ -1,8 +1,8 @@
#include "core/rendering/fade.h" #include "core/rendering/fade.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <stdlib.h> // for rand
#include <cstdlib> // for rand
#include <iostream> // for char_traits, basic_ostream, operator<< #include <iostream> // for char_traits, basic_ostream, operator<<
#include "game/defaults.hpp" // for GAMECANVAS_HEIGHT, GAMECANVAS_WIDTH #include "game/defaults.hpp" // for GAMECANVAS_HEIGHT, GAMECANVAS_WIDTH
@@ -15,7 +15,7 @@ Fade::Fade(SDL_Renderer *renderer)
SDL_SetTextureScaleMode(mBackbuffer, SDL_SCALEMODE_NEAREST); SDL_SetTextureScaleMode(mBackbuffer, SDL_SCALEMODE_NEAREST);
} }
if (mBackbuffer == nullptr) { if (mBackbuffer == nullptr) {
std::cout << "Error: textTexture could not be created!\nSDL Error: " << SDL_GetError() << std::endl; std::cout << "Error: textTexture could not be created!\nSDL Error: " << SDL_GetError() << '\n';
} }
} }
@@ -92,8 +92,9 @@ void Fade::render() {
SDL_RenderFillRect(mRenderer, &fR2); SDL_RenderFillRect(mRenderer, &fR2);
} }
if ((mCounter * 4) > GAMECANVAS_HEIGHT) if ((mCounter * 4) > GAMECANVAS_HEIGHT) {
mFinished = true; mFinished = true;
}
break; break;
} }
@@ -145,9 +146,10 @@ void Fade::render() {
// Actualiza las variables internas // Actualiza las variables internas
void Fade::update() { void Fade::update() {
if (mEnabled) if (mEnabled) {
mCounter++; mCounter++;
} }
}
// Activa el fade // Activa el fade
void Fade::activateFade() { void Fade::activateFade() {
@@ -163,12 +165,12 @@ void Fade::activateFade() {
} }
// Comprueba si está activo // Comprueba si está activo
bool Fade::isEnabled() { auto Fade::isEnabled() const -> bool {
return mEnabled; return mEnabled;
} }
// Comprueba si ha terminado la transicion // Comprueba si ha terminado la transicion
bool Fade::hasEnded() { auto Fade::hasEnded() const -> bool {
return mFinished; return mFinished;
} }
+2 -2
View File
@@ -44,10 +44,10 @@ class Fade {
void activateFade(); void activateFade();
// Comprueba si ha terminado la transicion // Comprueba si ha terminado la transicion
bool hasEnded(); [[nodiscard]] auto hasEnded() const -> bool;
// Comprueba si está activo // Comprueba si está activo
bool isEnabled(); [[nodiscard]] auto isEnabled() const -> bool;
// Establece el tipo de fade // Establece el tipo de fade
void setFadeType(Uint8 fadeType); void setFadeType(Uint8 fadeType);
+26 -34
View File
@@ -12,31 +12,22 @@ MovingSprite::MovingSprite(float x, float y, int w, int h, float velx, float vel
vx(velx), vx(velx),
vy(vely), vy(vely),
ax(accelx), ax(accelx),
ay(accely), ay(accely) {
zoomW(1),
zoomH(1),
angle(0.0),
rotateEnabled(false),
rotateSpeed(0),
rotateAmount(0.0),
counter(0),
center(nullptr),
currentFlip(SDL_FLIP_NONE) {
} }
// Reinicia todas las variables // Reinicia todas las variables
void MovingSprite::clear() { void MovingSprite::clear() {
x = 0.0f; // Posición en el eje X x = 0.0F; // Posición en el eje X
y = 0.0f; // Posición en el eje Y y = 0.0F; // Posición en el eje Y
vx = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse vx = 0.0F; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
vy = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse vy = 0.0F; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
ax = 0.0f; // Aceleración en el eje X. Variación de la velocidad ax = 0.0F; // Aceleración en el eje X. Variación de la velocidad
ay = 0.0f; // Aceleración en el eje Y. Variación de la velocidad ay = 0.0F; // Aceleración en el eje Y. Variación de la velocidad
zoomW = 1.0f; // Zoom aplicado a la anchura zoomW = 1.0F; // Zoom aplicado a la anchura
zoomH = 1.0f; // Zoom aplicado a la altura zoomH = 1.0F; // Zoom aplicado a la altura
angle = 0.0; // Angulo para dibujarlo angle = 0.0; // Angulo para dibujarlo
rotateEnabled = false; // Indica si ha de rotar rotateEnabled = false; // Indica si ha de rotar
@@ -71,48 +62,48 @@ void MovingSprite::render() {
// Obtiene el valor de la variable // Obtiene el valor de la variable
// cppcheck-suppress duplInheritedMember // cppcheck-suppress duplInheritedMember
float MovingSprite::getPosX() { auto MovingSprite::getPosX() const -> float {
return x; return x;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
// cppcheck-suppress duplInheritedMember // cppcheck-suppress duplInheritedMember
float MovingSprite::getPosY() { auto MovingSprite::getPosY() const -> float {
return y; return y;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
float MovingSprite::getVelX() { auto MovingSprite::getVelX() const -> float {
return vx; return vx;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
float MovingSprite::getVelY() { auto MovingSprite::getVelY() const -> float {
return vy; return vy;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
float MovingSprite::getAccelX() { auto MovingSprite::getAccelX() const -> float {
return ax; return ax;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
float MovingSprite::getAccelY() { auto MovingSprite::getAccelY() const -> float {
return ay; return ay;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
float MovingSprite::getZoomW() { auto MovingSprite::getZoomW() const -> float {
return zoomW; return zoomW;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
float MovingSprite::getZoomH() { auto MovingSprite::getZoomH() const -> float {
return zoomH; return zoomH;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
double MovingSprite::getAngle() { auto MovingSprite::getAngle() const -> double {
return angle; return angle;
} }
@@ -180,24 +171,25 @@ void MovingSprite::decAngle(double value) {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool MovingSprite::getRotate() { auto MovingSprite::getRotate() const -> bool {
return rotateEnabled; return rotateEnabled;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
Uint16 MovingSprite::getRotateSpeed() { auto MovingSprite::getRotateSpeed() const -> Uint16 {
return rotateSpeed; return rotateSpeed;
} }
// Establece la rotacion // Establece la rotacion
void MovingSprite::rotate() { void MovingSprite::rotate() {
if (enabled) if (enabled) {
if (rotateEnabled) { if (rotateEnabled) {
if (counter % rotateSpeed == 0) { if (counter % rotateSpeed == 0) {
incAngle(rotateAmount); incAngle(rotateAmount);
} }
} }
} }
}
// Establece el valor de la variable // Establece el valor de la variable
void MovingSprite::setRotate(bool value) { void MovingSprite::setRotate(bool value) {
@@ -250,12 +242,12 @@ void MovingSprite::flip() {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
SDL_FlipMode MovingSprite::getFlip() { auto MovingSprite::getFlip() -> SDL_FlipMode {
return currentFlip; return currentFlip;
} }
// Devuelve el rectangulo donde está el sprite // Devuelve el rectangulo donde está el sprite
SDL_Rect MovingSprite::getRect() { auto MovingSprite::getRect() -> SDL_Rect {
const SDL_Rect rect = {(int)x, (int)y, w, h}; const SDL_Rect rect = {(int)x, (int)y, w, h};
return rect; return rect;
} }
@@ -278,10 +270,10 @@ void MovingSprite::undoMoveY() {
// Pone a cero las velocidades de desplacamiento // Pone a cero las velocidades de desplacamiento
void MovingSprite::clearVel() { void MovingSprite::clearVel() {
vx = vy = 0.0f; vx = vy = 0.0F;
} }
// Devuelve el incremento en el eje X en pixels // Devuelve el incremento en el eje X en pixels
int MovingSprite::getIncX() { auto MovingSprite::getIncX() const -> int {
return (int)x - (int)xPrev; return (int)x - (int)xPrev;
} }
+24 -24
View File
@@ -22,16 +22,16 @@ class MovingSprite : public Sprite {
float ax; // Aceleración en el eje X. Variación de la velocidad float ax; // Aceleración en el eje X. Variación de la velocidad
float ay; // Aceleración en el eje Y. Variación de la velocidad float ay; // Aceleración en el eje Y. Variación de la velocidad
float zoomW; // Zoom aplicado a la anchura float zoomW{1}; // Zoom aplicado a la anchura
float zoomH; // Zoom aplicado a la altura float zoomH{1}; // Zoom aplicado a la altura
double angle; // Angulo para dibujarlo double angle{0.0}; // Angulo para dibujarlo
bool rotateEnabled; // Indica si ha de rotar bool rotateEnabled{false}; // Indica si ha de rotar
int rotateSpeed; // Velocidad de giro int rotateSpeed{0}; // Velocidad de giro
double rotateAmount; // Cantidad de grados a girar en cada iteración double rotateAmount{0.0}; // Cantidad de grados a girar en cada iteración
int counter; // Contador interno int counter{0}; // Contador interno
SDL_Point *center; // Centro de rotación SDL_Point *center{nullptr}; // Centro de rotación
SDL_FlipMode currentFlip; // Indica como se voltea el sprite SDL_FlipMode currentFlip{SDL_FLIP_NONE}; // Indica como se voltea el sprite
public: public:
// Constructor // Constructor
@@ -54,38 +54,38 @@ class MovingSprite : public Sprite {
// Obten el valor de la variable // Obten el valor de la variable
// cppcheck-suppress duplInheritedMember // cppcheck-suppress duplInheritedMember
float getPosX(); [[nodiscard]] auto getPosX() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
// cppcheck-suppress duplInheritedMember // cppcheck-suppress duplInheritedMember
float getPosY(); [[nodiscard]] auto getPosY() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
float getVelX(); [[nodiscard]] auto getVelX() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
float getVelY(); [[nodiscard]] auto getVelY() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
float getAccelX(); [[nodiscard]] auto getAccelX() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
float getAccelY(); [[nodiscard]] auto getAccelY() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
float getZoomW(); [[nodiscard]] auto getZoomW() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
float getZoomH(); [[nodiscard]] auto getZoomH() const -> float;
// Obten el valor de la variable // Obten el valor de la variable
double getAngle(); [[nodiscard]] auto getAngle() const -> double;
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool getRotate(); [[nodiscard]] auto getRotate() const -> bool;
// Obtiene el valor de la variable // Obtiene el valor de la variable
Uint16 getRotateSpeed(); [[nodiscard]] auto getRotateSpeed() const -> Uint16;
// Establece la posición y el tamaño del objeto // Establece la posición y el tamaño del objeto
void setRect(SDL_Rect rect) override; void setRect(SDL_Rect rect) override;
@@ -115,7 +115,7 @@ class MovingSprite : public Sprite {
void setZoomH(float value); void setZoomH(float value);
// Establece el valor de la variable // Establece el valor de la variable
void setAngle(double vaue); void setAngle(double value);
// Incrementa el valor de la variable // Incrementa el valor de la variable
void incAngle(double value); void incAngle(double value);
@@ -145,10 +145,10 @@ class MovingSprite : public Sprite {
void flip(); void flip();
// Obtiene el valor de la variable // Obtiene el valor de la variable
SDL_FlipMode getFlip(); auto getFlip() -> SDL_FlipMode;
// Devuelve el rectangulo donde está el sprite // Devuelve el rectangulo donde está el sprite
SDL_Rect getRect() override; auto getRect() -> SDL_Rect override;
// Deshace el último movimiento // Deshace el último movimiento
void undoMove(); void undoMove();
@@ -163,5 +163,5 @@ class MovingSprite : public Sprite {
void clearVel(); void clearVel();
// Devuelve el incremento en el eje X en pixels // Devuelve el incremento en el eje X en pixels
int getIncX(); [[nodiscard]] auto getIncX() const -> int;
}; };
+7 -6
View File
@@ -3,6 +3,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <algorithm> // for max, min #include <algorithm> // for max, min
#include <cmath> // for lround
#include <cstring> // for memcpy #include <cstring> // for memcpy
#include <iostream> // for basic_ostream, operator<<, cout, endl #include <iostream> // for basic_ostream, operator<<, cout, endl
#include <string> // for basic_string, char_traits, string #include <string> // for basic_string, char_traits, string
@@ -108,7 +109,7 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
} }
if (gameCanvas == nullptr) { if (gameCanvas == nullptr) {
if (Options::settings.console) { if (Options::settings.console) {
std::cout << "gameCanvas could not be created!\nSDL Error: " << SDL_GetError() << std::endl; std::cout << "gameCanvas could not be created!\nSDL Error: " << SDL_GetError() << '\n';
} }
} }
@@ -351,7 +352,7 @@ void Screen::applyFullscreen(bool fullscreen) {
void Screen::applyWindowedLayout() { void Screen::applyWindowedLayout() {
windowWidth = gameCanvasWidth; windowWidth = gameCanvasWidth;
windowHeight = gameCanvasHeight; windowHeight = gameCanvasHeight;
dest = {0, 0, gameCanvasWidth, gameCanvasHeight}; dest = {.x = 0, .y = 0, .w = gameCanvasWidth, .h = gameCanvasHeight};
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
windowWidth *= WASM_RENDER_SCALE; windowWidth *= WASM_RENDER_SCALE;
@@ -396,12 +397,12 @@ void Screen::computeFullscreenGameRect() {
float ratio = (float)gameCanvasWidth / (float)gameCanvasHeight; float ratio = (float)gameCanvasWidth / (float)gameCanvasHeight;
if ((windowWidth - gameCanvasWidth) >= (windowHeight - gameCanvasHeight)) { if ((windowWidth - gameCanvasWidth) >= (windowHeight - gameCanvasHeight)) {
dest.h = windowHeight; dest.h = windowHeight;
dest.w = (int)((windowHeight * ratio) + 0.5f); dest.w = static_cast<int>(std::lround(windowHeight * ratio));
dest.x = (windowWidth - dest.w) / 2; dest.x = (windowWidth - dest.w) / 2;
dest.y = (windowHeight - dest.h) / 2; dest.y = (windowHeight - dest.h) / 2;
} else { } else {
dest.w = windowWidth; dest.w = windowWidth;
dest.h = (int)((windowWidth / ratio) + 0.5f); dest.h = static_cast<int>(std::lround(windowWidth / ratio));
dest.x = (windowWidth - dest.w) / 2; dest.x = (windowWidth - dest.w) / 2;
dest.y = (windowHeight - dest.h) / 2; dest.y = (windowHeight - dest.h) / 2;
} }
@@ -579,7 +580,7 @@ void Screen::toggleShaderEnabled() {
setShaderEnabled(!Options::video.shader.enabled); setShaderEnabled(!Options::video.shader.enabled);
} }
auto Screen::isShaderEnabled() const -> bool { auto Screen::isShaderEnabled() -> bool {
return Options::video.shader.enabled; return Options::video.shader.enabled;
} }
@@ -595,7 +596,7 @@ void Screen::setActiveShader(Rendering::ShaderType type) {
notify(type == Rendering::ShaderType::CRTPI ? "Shader: CRTPI" : "Shader: POSTFX", MAGENTA, BLACK, DUR_MS); notify(type == Rendering::ShaderType::CRTPI ? "Shader: CRTPI" : "Shader: POSTFX", MAGENTA, BLACK, DUR_MS);
} }
auto Screen::getActiveShader() const -> Rendering::ShaderType { auto Screen::getActiveShader() -> Rendering::ShaderType {
return Options::video.shader.current_shader; return Options::video.shader.current_shader;
} }
#endif #endif
+5 -5
View File
@@ -46,7 +46,7 @@ class Screen {
void setVideoMode(bool fullscreen); // Establece el modo de video void setVideoMode(bool fullscreen); // Establece el modo de video
void toggleVideoMode(); // Cambia entre pantalla completa y ventana void toggleVideoMode(); // Cambia entre pantalla completa y ventana
void handleCanvasResized(); // En Emscripten, reaplica setVideoMode tras un cambio del navegador (salida de fullscreen con Esc, rotación). No-op fuera de Emscripten void handleCanvasResized(); // En Emscripten, reaplica setVideoMode tras un cambio del navegador (salida de fullscreen con Esc, rotación). No-op fuera de Emscripten
void syncFullscreenFlagFromBrowser(bool isFullscreen); // Sincroniza el flag interno de fullscreen con el estado real del navegador. Debe llamarse antes de diferir handleCanvasResized. No-op fuera de Emscripten static void syncFullscreenFlagFromBrowser(bool isFullscreen); // Sincroniza el flag interno de fullscreen con el estado real del navegador. Debe llamarse antes de diferir handleCanvasResized. No-op fuera de Emscripten
void toggleIntegerScale(); // Alterna el escalado entero void toggleIntegerScale(); // Alterna el escalado entero
void setIntegerScale(bool enabled); // Establece el escalado entero void setIntegerScale(bool enabled); // Establece el escalado entero
void toggleVSync(); // Alterna el V-Sync void toggleVSync(); // Alterna el V-Sync
@@ -66,13 +66,13 @@ class Screen {
// GPU / shaders (post-procesado). En builds con NO_SHADERS (Emscripten) son no-op. // GPU / shaders (post-procesado). En builds con NO_SHADERS (Emscripten) son no-op.
void initShaders(); // Crea el backend GPU si no existe y lo inicializa void initShaders(); // Crea el backend GPU si no existe y lo inicializa
void shutdownShaders(); // Libera el backend GPU void shutdownShaders(); // Libera el backend GPU
auto isGpuAccelerated() const -> bool; // true si el backend existe y reporta hardware OK [[nodiscard]] auto isGpuAccelerated() const -> bool; // true si el backend existe y reporta hardware OK
void setShaderEnabled(bool enabled); // Activa o desactiva el post-procesado (persiste) void setShaderEnabled(bool enabled); // Activa o desactiva el post-procesado (persiste)
void toggleShaderEnabled(); // Alterna post-procesado void toggleShaderEnabled(); // Alterna post-procesado
auto isShaderEnabled() const -> bool; // Estado actual (lee options) [[nodiscard]] static auto isShaderEnabled() -> bool; // Estado actual (lee options)
#ifndef NO_SHADERS #ifndef NO_SHADERS
void setActiveShader(Rendering::ShaderType type); // POSTFX o CRTPI void setActiveShader(Rendering::ShaderType type); // POSTFX o CRTPI
auto getActiveShader() const -> Rendering::ShaderType; [[nodiscard]] static auto getActiveShader() -> Rendering::ShaderType;
#endif #endif
void toggleActiveShader(); // Alterna POSTFX ↔ CRTPI void toggleActiveShader(); // Alterna POSTFX ↔ CRTPI
@@ -80,7 +80,7 @@ class Screen {
// Retornen false si GPU off / shaders off / llista buida (igual que a aee_plus). // Retornen false si GPU off / shaders off / llista buida (igual que a aee_plus).
auto nextPreset() -> bool; auto nextPreset() -> bool;
auto prevPreset() -> bool; auto prevPreset() -> bool;
auto getCurrentPresetName() const -> const char *; [[nodiscard]] auto getCurrentPresetName() const -> const char *;
void applyCurrentPostFXPreset(); // Escriu el preset PostFX actiu al backend void applyCurrentPostFXPreset(); // Escriu el preset PostFX actiu al backend
void applyCurrentCrtPiPreset(); // Escriu el preset CrtPi actiu al backend void applyCurrentCrtPiPreset(); // Escriu el preset CrtPi actiu al backend
@@ -762,7 +762,7 @@ namespace Rendering {
} }
// Copia directa — el upscale lo hace la GPU en el primer render pass // Copia directa — el upscale lo hace la GPU en el primer render pass
std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4)); std::memcpy(mapped, pixels, static_cast<size_t>(width) * height * 4);
SDL_UnmapGPUTransferBuffer(device_, upload_buffer_); SDL_UnmapGPUTransferBuffer(device_, upload_buffer_);
} }
+2 -1
View File
@@ -2,13 +2,14 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <cstdint>
#include <string> #include <string>
#include <utility> #include <utility>
namespace Rendering { namespace Rendering {
/** @brief Identificador del shader de post-procesado activo */ /** @brief Identificador del shader de post-procesado activo */
enum class ShaderType { POSTFX, enum class ShaderType : std::uint8_t { POSTFX,
CRTPI }; CRTPI };
/** /**
+16 -16
View File
@@ -27,8 +27,8 @@ void SmartSprite::init() {
// Actualiza la posición y comprueba si ha llegado a su destino // Actualiza la posición y comprueba si ha llegado a su destino
void SmartSprite::update() { void SmartSprite::update() {
if (enabled) { if (enabled) {
// Actualiza las variables internas del objeto // Actualiza animació + posició (delegant en AnimatedSprite::update)
MovingSprite::update(); AnimatedSprite::update();
// Comprueba el movimiento // Comprueba el movimiento
checkMove(); checkMove();
@@ -47,7 +47,7 @@ void SmartSprite::render() {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
int SmartSprite::getEnabledCounter() { auto SmartSprite::getEnabledCounter() const -> int {
return enabledCounter; return enabledCounter;
} }
@@ -67,12 +67,12 @@ void SmartSprite::setDestY(int y) {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
int SmartSprite::getDestX() { auto SmartSprite::getDestX() const -> int {
return destX; return destX;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
int SmartSprite::getDestY() { auto SmartSprite::getDestY() const -> int {
return destY; return destY;
} }
@@ -86,8 +86,8 @@ void SmartSprite::checkMove() {
setPosX(destX); setPosX(destX);
// Lo detiene // Lo detiene
setVelX(0.0f); setVelX(0.0F);
setAccelX(0.0f); setAccelX(0.0F);
} }
} }
// Comprueba si se desplaza en el eje X hacia la izquierda // Comprueba si se desplaza en el eje X hacia la izquierda
@@ -98,8 +98,8 @@ void SmartSprite::checkMove() {
setPosX(destX); setPosX(destX);
// Lo detiene // Lo detiene
setVelX(0.0f); setVelX(0.0F);
setAccelX(0.0f); setAccelX(0.0F);
} }
} }
@@ -111,8 +111,8 @@ void SmartSprite::checkMove() {
setPosY(destY); setPosY(destY);
// Lo detiene // Lo detiene
setVelY(0.0f); setVelY(0.0F);
setAccelY(0.0f); setAccelY(0.0F);
} }
} }
// Comprueba si se desplaza en el eje Y hacia arriba // Comprueba si se desplaza en el eje Y hacia arriba
@@ -123,8 +123,8 @@ void SmartSprite::checkMove() {
setPosY(destY); setPosY(destY);
// Lo detiene // Lo detiene
setVelY(0.0f); setVelY(0.0F);
setAccelY(0.0f); setAccelY(0.0F);
} }
} }
} }
@@ -132,7 +132,7 @@ void SmartSprite::checkMove() {
// Comprueba si ha terminado // Comprueba si ha terminado
void SmartSprite::checkFinished() { void SmartSprite::checkFinished() {
// Comprueba si ha llegado a su destino // Comprueba si ha llegado a su destino
onDestination = (getPosX() == destX && getPosY() == destY) ? true : false; onDestination = getPosX() == destX && getPosY() == destY;
if (onDestination) { // Si esta en el destino comprueba su contador if (onDestination) { // Si esta en el destino comprueba su contador
if (enabledCounter == 0) { // Si ha llegado a cero, deshabilita el objeto y lo marca como finalizado if (enabledCounter == 0) { // Si ha llegado a cero, deshabilita el objeto y lo marca como finalizado
@@ -144,11 +144,11 @@ void SmartSprite::checkFinished() {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool SmartSprite::isOnDestination() { auto SmartSprite::isOnDestination() const -> bool {
return onDestination; return onDestination;
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool SmartSprite::hasFinished() { auto SmartSprite::hasFinished() const -> bool {
return finished; return finished;
} }
+5 -5
View File
@@ -35,7 +35,7 @@ class SmartSprite : public AnimatedSprite {
void render() override; void render() override;
// Obtiene el valor de la variable // Obtiene el valor de la variable
int getEnabledCounter(); [[nodiscard]] auto getEnabledCounter() const -> int;
// Establece el valor de la variable // Establece el valor de la variable
void setEnabledCounter(int value); void setEnabledCounter(int value);
@@ -47,14 +47,14 @@ class SmartSprite : public AnimatedSprite {
void setDestY(int y); void setDestY(int y);
// Obtiene el valor de la variable // Obtiene el valor de la variable
int getDestX(); [[nodiscard]] auto getDestX() const -> int;
// Obtiene el valor de la variable // Obtiene el valor de la variable
int getDestY(); [[nodiscard]] auto getDestY() const -> int;
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool isOnDestination(); [[nodiscard]] auto isOnDestination() const -> bool;
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool hasFinished(); [[nodiscard]] auto hasFinished() const -> bool;
}; };
+10 -10
View File
@@ -39,22 +39,22 @@ void Sprite::render() {
} }
// Obten el valor de la variable // Obten el valor de la variable
int Sprite::getPosX() { auto Sprite::getPosX() const -> int {
return x; return x;
} }
// Obten el valor de la variable // Obten el valor de la variable
int Sprite::getPosY() { auto Sprite::getPosY() const -> int {
return y; return y;
} }
// Obten el valor de la variable // Obten el valor de la variable
int Sprite::getWidth() { auto Sprite::getWidth() const -> int {
return w; return w;
} }
// Obten el valor de la variable // Obten el valor de la variable
int Sprite::getHeight() { auto Sprite::getHeight() const -> int {
return h; return h;
} }
@@ -85,7 +85,7 @@ void Sprite::setHeight(int h) {
} }
// Obten el valor de la variable // Obten el valor de la variable
SDL_Rect Sprite::getSpriteClip() { auto Sprite::getSpriteClip() -> SDL_Rect {
return spriteClip; return spriteClip;
} }
@@ -96,11 +96,11 @@ void Sprite::setSpriteClip(SDL_Rect rect) {
// Establece el valor de la variable // Establece el valor de la variable
void Sprite::setSpriteClip(int x, int y, int w, int h) { void Sprite::setSpriteClip(int x, int y, int w, int h) {
spriteClip = {x, y, w, h}; spriteClip = {.x = x, .y = y, .w = w, .h = h};
} }
// Obten el valor de la variable // Obten el valor de la variable
Texture *Sprite::getTexture() { auto Sprite::getTexture() -> Texture * {
return texture; return texture;
} }
@@ -110,7 +110,7 @@ void Sprite::setTexture(Texture *texture) {
} }
// Obten el valor de la variable // Obten el valor de la variable
SDL_Renderer *Sprite::getRenderer() { auto Sprite::getRenderer() -> SDL_Renderer * {
return renderer; return renderer;
} }
@@ -125,12 +125,12 @@ void Sprite::setEnabled(bool value) {
} }
// Comprueba si el objeto está habilitado // Comprueba si el objeto está habilitado
bool Sprite::isEnabled() { auto Sprite::isEnabled() -> bool {
return enabled; return enabled;
} }
// Devuelve el rectangulo donde está el sprite // Devuelve el rectangulo donde está el sprite
SDL_Rect Sprite::getRect() { auto Sprite::getRect() -> SDL_Rect {
SDL_Rect rect = {x, y, w, h}; SDL_Rect rect = {x, y, w, h};
return rect; return rect;
} }
+9 -9
View File
@@ -29,16 +29,16 @@ class Sprite {
virtual void render(); virtual void render();
// Obten el valor de la variable // Obten el valor de la variable
int getPosX(); [[nodiscard]] auto getPosX() const -> int;
// Obten el valor de la variable // Obten el valor de la variable
int getPosY(); [[nodiscard]] auto getPosY() const -> int;
// Obten el valor de la variable // Obten el valor de la variable
int getWidth(); [[nodiscard]] auto getWidth() const -> int;
// Obten el valor de la variable // Obten el valor de la variable
int getHeight(); [[nodiscard]] auto getHeight() const -> int;
// Establece la posición del objeto // Establece la posición del objeto
void setPos(SDL_Rect rect); void setPos(SDL_Rect rect);
@@ -56,7 +56,7 @@ class Sprite {
void setHeight(int h); void setHeight(int h);
// Obten el valor de la variable // Obten el valor de la variable
SDL_Rect getSpriteClip(); auto getSpriteClip() -> SDL_Rect;
// Establece el valor de la variable // Establece el valor de la variable
void setSpriteClip(SDL_Rect rect); void setSpriteClip(SDL_Rect rect);
@@ -65,13 +65,13 @@ class Sprite {
void setSpriteClip(int x, int y, int w, int h); void setSpriteClip(int x, int y, int w, int h);
// Obten el valor de la variable // Obten el valor de la variable
Texture *getTexture(); auto getTexture() -> Texture *;
// Establece el valor de la variable // Establece el valor de la variable
void setTexture(Texture *texture); void setTexture(Texture *texture);
// Obten el valor de la variable // Obten el valor de la variable
SDL_Renderer *getRenderer(); auto getRenderer() -> SDL_Renderer *;
// Establece el valor de la variable // Establece el valor de la variable
void setRenderer(SDL_Renderer *renderer); void setRenderer(SDL_Renderer *renderer);
@@ -80,10 +80,10 @@ class Sprite {
virtual void setEnabled(bool value); virtual void setEnabled(bool value);
// Comprueba si el objeto está habilitado // Comprueba si el objeto está habilitado
virtual bool isEnabled(); virtual auto isEnabled() -> bool;
// Devuelve el rectangulo donde está el sprite // Devuelve el rectangulo donde está el sprite
virtual SDL_Rect getRect(); virtual auto getRect() -> SDL_Rect;
// Establece los valores de posición y tamaño del sprite // Establece los valores de posición y tamaño del sprite
virtual void setRect(SDL_Rect rect); virtual void setRect(SDL_Rect rect);
+22 -22
View File
@@ -39,25 +39,25 @@ static void computeTextFileOffsets(textFile_t &tf) {
} }
// Llena una estructuta textFile_t desde un fichero // Llena una estructuta textFile_t desde un fichero
textFile_t LoadTextFile(const std::string &file, bool verbose) { auto LoadTextFile(const std::string &file, bool verbose) -> textFile_t {
textFile_t tf; textFile_t tf;
tf.boxWidth = 0; tf.boxWidth = 0;
tf.boxHeight = 0; tf.boxHeight = 0;
for (int i = 0; i < 128; ++i) { for (auto &i : tf.offset) {
tf.offset[i].x = 0; i.x = 0;
tf.offset[i].y = 0; i.y = 0;
tf.offset[i].w = 0; i.w = 0;
} }
const std::string filename = file.substr(file.find_last_of("\\/") + 1).c_str(); const std::string filename = file.substr(file.find_last_of("\\/") + 1);
std::ifstream rfile(file); std::ifstream rfile(file);
if (rfile.is_open() && rfile.good()) { if (rfile.is_open() && rfile.good()) {
parseTextFileStream(rfile, tf); parseTextFileStream(rfile, tf);
if (verbose) { if (verbose) {
std::cout << "Text loaded: " << filename.c_str() << std::endl; std::cout << "Text loaded: " << filename.c_str() << '\n';
} }
} else if (verbose) { } else if (verbose) {
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl; std::cout << "Warning: Unable to open " << filename.c_str() << " file" << '\n';
} }
computeTextFileOffsets(tf); computeTextFileOffsets(tf);
@@ -65,21 +65,21 @@ textFile_t LoadTextFile(const std::string &file, bool verbose) {
} }
// Llena una estructura textFile_t desde bytes en memoria // Llena una estructura textFile_t desde bytes en memoria
textFile_t LoadTextFileFromMemory(const std::vector<uint8_t> &bytes, bool verbose) { auto LoadTextFileFromMemory(const std::vector<uint8_t> &bytes, bool verbose) -> textFile_t {
textFile_t tf; textFile_t tf;
tf.boxWidth = 0; tf.boxWidth = 0;
tf.boxHeight = 0; tf.boxHeight = 0;
for (int i = 0; i < 128; ++i) { for (auto &i : tf.offset) {
tf.offset[i].x = 0; i.x = 0;
tf.offset[i].y = 0; i.y = 0;
tf.offset[i].w = 0; i.w = 0;
} }
if (!bytes.empty()) { if (!bytes.empty()) {
std::string content(reinterpret_cast<const char *>(bytes.data()), bytes.size()); std::string content(reinterpret_cast<const char *>(bytes.data()), bytes.size());
std::stringstream ss(content); std::stringstream ss(content);
parseTextFileStream(ss, tf); parseTextFileStream(ss, tf);
if (verbose) { if (verbose) {
std::cout << "Text loaded from memory" << std::endl; std::cout << "Text loaded from memory" << '\n';
} }
} }
computeTextFileOffsets(tf); computeTextFileOffsets(tf);
@@ -170,10 +170,9 @@ Text::Text(const std::vector<uint8_t> &pngBytes, const std::vector<uint8_t> &txt
// Destructor // Destructor
Text::~Text() { Text::~Text() {
delete sprite; delete sprite;
if (texture != nullptr) {
delete texture; delete texture;
} }
}
// 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) {
@@ -187,11 +186,11 @@ void Text::write(int x, int y, const std::string &text, int kerning, int lenght)
const int width = sprite->getWidth(); const int width = sprite->getWidth();
const int height = sprite->getHeight(); const int height = sprite->getHeight();
for (int i = 0; i < lenght; ++i) { for (int i = 0; i < lenght; ++i) {
const int index = text[i]; const int index = static_cast<unsigned char>(text[i]);
sprite->setSpriteClip(offset[index].x, offset[index].y, width, height); sprite->setSpriteClip(offset[index].x, offset[index].y, width, height);
sprite->setPosX(x + shift); sprite->setPosX(x + shift);
sprite->render(); sprite->render();
shift += fixedWidth ? boxWidth : (offset[int(text[i])].w + kerning); shift += fixedWidth ? boxWidth : (offset[index].w + kerning);
} }
} }
@@ -249,18 +248,19 @@ void Text::writeDX(Uint8 flags, int x, int y, const std::string &text, int kerni
} }
// Obtiene la longitud en pixels de una cadena // Obtiene la longitud en pixels de una cadena
int Text::lenght(const std::string &text, int kerning) { auto Text::lenght(const std::string &text, int kerning) -> int {
int shift = 0; int shift = 0;
for (int i = 0; i < (int)text.length(); ++i) for (int i = 0; i < (int)text.length(); ++i) {
shift += (offset[int(text[i])].w + kerning); shift += (offset[static_cast<unsigned char>(text[i])].w + kerning);
}
// Descuenta el kerning del último caracter // Descuenta el kerning del último caracter
return shift - kerning; return shift - kerning;
} }
// Devuelve el valor de la variable // Devuelve el valor de la variable
int Text::getCharacterSize() { auto Text::getCharacterSize() const -> int {
return boxWidth; return boxWidth;
} }
+5 -5
View File
@@ -28,10 +28,10 @@ struct textFile_t {
}; };
// Llena una estructuta textFile_t desde un fichero // Llena una estructuta textFile_t desde un fichero
textFile_t LoadTextFile(const std::string &file, bool verbose = false); auto LoadTextFile(const std::string &file, bool verbose = false) -> textFile_t;
// Llena una estructura textFile_t desde bytes en memoria // Llena una estructura textFile_t desde bytes en memoria
textFile_t LoadTextFileFromMemory(const std::vector<uint8_t> &bytes, bool verbose = false); auto LoadTextFileFromMemory(const std::vector<uint8_t> &bytes, bool verbose = false) -> textFile_t;
// Clase texto. Pinta texto en pantalla a partir de un bitmap // Clase texto. Pinta texto en pantalla a partir de un bitmap
class Text { class Text {
@@ -60,7 +60,7 @@ class Text {
// No copiable (gestiona memoria dinámica) // No copiable (gestiona memoria dinámica)
Text(const Text &) = delete; Text(const Text &) = delete;
Text &operator=(const Text &) = delete; auto operator=(const Text &) -> Text & = delete;
// Escribe el texto en pantalla // Escribe el texto en pantalla
void write(int x, int y, const std::string &text, int kerning = 1, int lenght = -1); void write(int x, int y, const std::string &text, int kerning = 1, int lenght = -1);
@@ -78,10 +78,10 @@ class Text {
void writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning = 1, color_t textColor = color_t(255, 255, 255), Uint8 shadowDistance = 1, color_t shadowColor = color_t(0, 0, 0), int lenght = -1); void writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning = 1, color_t textColor = color_t(255, 255, 255), Uint8 shadowDistance = 1, color_t shadowColor = color_t(0, 0, 0), int lenght = -1);
// Obtiene la longitud en pixels de una cadena // Obtiene la longitud en pixels de una cadena
int lenght(const std::string &text, int kerning = 1); auto lenght(const std::string &text, int kerning = 1) -> int;
// Devuelve el valor de la variable // Devuelve el valor de la variable
int getCharacterSize(); [[nodiscard]] auto getCharacterSize() const -> int;
// Recarga la textura // Recarga la textura
void reLoadTexture(); void reLoadTexture();
+32 -21
View File
@@ -2,10 +2,11 @@
#include "core/rendering/texture.h" #include "core/rendering/texture.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <stdlib.h> // for exit
#include <cstdlib> // for exit
#include <iostream> // for basic_ostream, operator<<, cout, endl #include <iostream> // for basic_ostream, operator<<, cout, endl
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "core/resources/resource_helper.h" // for loadFile (pack + filesystem fallback)
#include "external/stb_image.h" // for stbi_failure_reason, stbi_image_free #include "external/stb_image.h" // for stbi_failure_reason, stbi_image_free
SDL_ScaleMode Texture::currentScaleMode = SDL_SCALEMODE_NEAREST; SDL_ScaleMode Texture::currentScaleMode = SDL_SCALEMODE_NEAREST;
@@ -32,8 +33,7 @@ Texture::Texture(SDL_Renderer *renderer, const std::vector<uint8_t> &bytes, bool
: texture(nullptr), : texture(nullptr),
renderer(renderer), renderer(renderer),
width(0), width(0),
height(0), height(0) {
path("") {
if (!bytes.empty()) { if (!bytes.empty()) {
loadFromMemory(bytes.data(), bytes.size(), renderer, verbose); loadFromMemory(bytes.data(), bytes.size(), renderer, verbose);
} }
@@ -46,7 +46,7 @@ Texture::~Texture() {
} }
// Helper: convierte píxeles RGBA decodificados por stbi en SDL_Texture // Helper: convierte píxeles RGBA decodificados por stbi en SDL_Texture
static SDL_Texture *createTextureFromPixels(SDL_Renderer *renderer, unsigned char *data, int w, int h, int *out_w, int *out_h) { static auto createTextureFromPixels(SDL_Renderer *renderer, unsigned char *data, int w, int h, int *out_w, int *out_h) -> SDL_Texture * {
const int pitch = 4 * w; const int pitch = 4 * w;
SDL_Surface *loadedSurface = SDL_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_RGBA32, static_cast<void *>(data), pitch); SDL_Surface *loadedSurface = SDL_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_RGBA32, static_cast<void *>(data), pitch);
if (loadedSurface == nullptr) { if (loadedSurface == nullptr) {
@@ -62,23 +62,32 @@ static SDL_Texture *createTextureFromPixels(SDL_Renderer *renderer, unsigned cha
return newTexture; return newTexture;
} }
// Carga una imagen desde un fichero // Carga una imagen desde un fichero (vía ResourceHelper: pack si està inicialitzat, filesystem si no)
bool Texture::loadFromFile(const std::string &path, SDL_Renderer *renderer, bool verbose) { auto Texture::loadFromFile(const std::string &path, SDL_Renderer *renderer, bool verbose) -> bool {
const std::string filename = path.substr(path.find_last_of("\\/") + 1); const std::string filename = path.substr(path.find_last_of("\\/") + 1);
auto bytes = ResourceHelper::loadFile(path);
if (bytes.empty()) {
SDL_Log("Loading image failed: can't open %s", path.c_str());
exit(1);
}
int req_format = STBI_rgb_alpha; int req_format = STBI_rgb_alpha;
int w, h, orig_format; int w;
unsigned char *data = stbi_load(path.c_str(), &w, &h, &orig_format, req_format); int h;
int orig_format;
unsigned char *data = stbi_load_from_memory(bytes.data(), static_cast<int>(bytes.size()), &w, &h, &orig_format, req_format);
if (data == nullptr) { if (data == nullptr) {
SDL_Log("Loading image failed: %s", stbi_failure_reason()); SDL_Log("Loading image failed: %s", stbi_failure_reason());
exit(1); exit(1);
} else if (verbose) { } else if (verbose) {
std::cout << "Image loaded: " << filename.c_str() << std::endl; std::cout << "Image loaded: " << filename.c_str() << '\n';
} }
unload(); unload();
SDL_Texture *newTexture = createTextureFromPixels(renderer, data, w, h, &this->width, &this->height); SDL_Texture *newTexture = createTextureFromPixels(renderer, data, w, h, &this->width, &this->height);
if (newTexture == nullptr && verbose) { if (newTexture == nullptr && verbose) {
std::cout << "Unable to load image " << path.c_str() << std::endl; std::cout << "Unable to load image " << path.c_str() << '\n';
} }
stbi_image_free(data); stbi_image_free(data);
@@ -87,8 +96,10 @@ bool Texture::loadFromFile(const std::string &path, SDL_Renderer *renderer, bool
} }
// Carga una imagen desde bytes en memoria // Carga una imagen desde bytes en memoria
bool Texture::loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *renderer, bool verbose) { auto Texture::loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *renderer, bool verbose) -> bool {
int w, h, orig_format; int w;
int h;
int orig_format;
unsigned char *pixels = stbi_load_from_memory(data, (int)size, &w, &h, &orig_format, STBI_rgb_alpha); unsigned char *pixels = stbi_load_from_memory(data, (int)size, &w, &h, &orig_format, STBI_rgb_alpha);
if (pixels == nullptr) { if (pixels == nullptr) {
SDL_Log("Loading image from memory failed: %s", stbi_failure_reason()); SDL_Log("Loading image from memory failed: %s", stbi_failure_reason());
@@ -98,7 +109,7 @@ bool Texture::loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *ren
unload(); unload();
SDL_Texture *newTexture = createTextureFromPixels(renderer, pixels, w, h, &this->width, &this->height); SDL_Texture *newTexture = createTextureFromPixels(renderer, pixels, w, h, &this->width, &this->height);
if (newTexture == nullptr && verbose) { if (newTexture == nullptr && verbose) {
std::cout << "Unable to create texture from memory" << std::endl; std::cout << "Unable to create texture from memory" << '\n';
} }
stbi_image_free(pixels); stbi_image_free(pixels);
@@ -107,11 +118,11 @@ bool Texture::loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *ren
} }
// Crea una textura en blanco // Crea una textura en blanco
bool Texture::createBlank(SDL_Renderer *renderer, int width, int height, SDL_TextureAccess access) { auto Texture::createBlank(SDL_Renderer *renderer, int width, int height, SDL_TextureAccess access) -> bool {
// Crea una textura sin inicializar // Crea una textura sin inicializar
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, access, width, height); texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, access, width, height);
if (texture == nullptr) { if (texture == nullptr) {
std::cout << "Unable to create blank texture! SDL Error: " << SDL_GetError() << std::endl; std::cout << "Unable to create blank texture! SDL Error: " << SDL_GetError() << '\n';
} else { } else {
this->width = width; this->width = width;
this->height = height; this->height = height;
@@ -165,7 +176,7 @@ void Texture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, float
SDL_FRect srcRect; SDL_FRect srcRect;
SDL_FRect *srcRectPtr = nullptr; SDL_FRect *srcRectPtr = nullptr;
if (clip != nullptr) { if (clip != nullptr) {
srcRect = {(float)clip->x, (float)clip->y, (float)clip->w, (float)clip->h}; srcRect = {.x = (float)clip->x, .y = (float)clip->y, .w = (float)clip->w, .h = (float)clip->h};
srcRectPtr = &srcRect; srcRectPtr = &srcRect;
} }
@@ -173,7 +184,7 @@ void Texture::render(SDL_Renderer *renderer, int x, int y, SDL_Rect *clip, float
SDL_FPoint fCenter; SDL_FPoint fCenter;
SDL_FPoint *fCenterPtr = nullptr; SDL_FPoint *fCenterPtr = nullptr;
if (center != nullptr) { if (center != nullptr) {
fCenter = {(float)center->x, (float)center->y}; fCenter = {.x = (float)center->x, .y = (float)center->y};
fCenterPtr = &fCenter; fCenterPtr = &fCenter;
} }
@@ -187,21 +198,21 @@ void Texture::setAsRenderTarget(SDL_Renderer *renderer) {
} }
// Obtiene el ancho de la imagen // Obtiene el ancho de la imagen
int Texture::getWidth() { auto Texture::getWidth() const -> int {
return width; return width;
} }
// Obtiene el alto de la imagen // Obtiene el alto de la imagen
int Texture::getHeight() { auto Texture::getHeight() const -> int {
return height; return height;
} }
// Recarga la textura // Recarga la textura
bool Texture::reLoad() { auto Texture::reLoad() -> bool {
return loadFromFile(path, renderer); return loadFromFile(path, renderer);
} }
// Obtiene la textura // Obtiene la textura
SDL_Texture *Texture::getSDLTexture() { auto Texture::getSDLTexture() -> SDL_Texture * {
return texture; return texture;
} }
+7 -7
View File
@@ -33,13 +33,13 @@ class Texture {
~Texture(); ~Texture();
// Carga una imagen desde un fichero // Carga una imagen desde un fichero
bool loadFromFile(const std::string &path, SDL_Renderer *renderer, bool verbose = false); auto loadFromFile(const std::string &path, SDL_Renderer *renderer, bool verbose = false) -> bool;
// Carga una imagen desde bytes en memoria // Carga una imagen desde bytes en memoria
bool loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *renderer, bool verbose = false); auto loadFromMemory(const uint8_t *data, size_t size, SDL_Renderer *renderer, bool verbose = false) -> bool;
// Crea una textura en blanco // Crea una textura en blanco
bool createBlank(SDL_Renderer *renderer, int width, int height, SDL_TextureAccess = SDL_TEXTUREACCESS_STREAMING); auto createBlank(SDL_Renderer *renderer, int width, int height, SDL_TextureAccess /*access*/ = SDL_TEXTUREACCESS_STREAMING) -> bool;
// Libera la memoria de la textura // Libera la memoria de la textura
void unload(); void unload();
@@ -60,14 +60,14 @@ class Texture {
void setAsRenderTarget(SDL_Renderer *renderer); void setAsRenderTarget(SDL_Renderer *renderer);
// Obtiene el ancho de la imagen // Obtiene el ancho de la imagen
int getWidth(); [[nodiscard]] auto getWidth() const -> int;
// Obtiene el alto de la imagen // Obtiene el alto de la imagen
int getHeight(); [[nodiscard]] auto getHeight() const -> int;
// Recarga la textura // Recarga la textura
bool reLoad(); auto reLoad() -> bool;
// Obtiene la textura // Obtiene la textura
SDL_Texture *getSDLTexture(); auto getSDLTexture() -> SDL_Texture *;
}; };
+4 -16
View File
@@ -4,19 +4,7 @@
// Constructor // Constructor
Writer::Writer(Text *text) Writer::Writer(Text *text)
: text(text), : text(text) {
posX(0),
posY(0),
kerning(0),
caption(""),
speed(0),
writingCounter(0),
index(0),
lenght(0),
completed(false),
enabled(false),
enabledCounter(0),
finished(false) {
} }
// Actualiza el objeto // Actualiza el objeto
@@ -87,7 +75,7 @@ void Writer::setEnabled(bool value) {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool Writer::IsEnabled() { auto Writer::IsEnabled() const -> bool {
return enabled; return enabled;
} }
@@ -97,7 +85,7 @@ void Writer::setEnabledCounter(int time) {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
int Writer::getEnabledCounter() { auto Writer::getEnabledCounter() const -> int {
return enabledCounter; return enabledCounter;
} }
@@ -107,6 +95,6 @@ void Writer::center(int x) {
} }
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool Writer::hasFinished() { auto Writer::hasFinished() const -> bool {
return finished; return finished;
} }
+14 -14
View File
@@ -10,18 +10,18 @@ class Writer {
Text *text; // Objeto encargado de escribir el texto Text *text; // Objeto encargado de escribir el texto
// Variables // Variables
int posX; // Posicion en el eje X donde empezar a escribir el texto int posX{0}; // Posicion en el eje X donde empezar a escribir el texto
int posY; // Posicion en el eje Y donde empezar a escribir el texto int posY{0}; // Posicion en el eje Y donde empezar a escribir el texto
int kerning; // Kerning del texto, es decir, espaciado entre caracteres int kerning{0}; // Kerning del texto, es decir, espaciado entre caracteres
std::string caption; // El texto para escribir std::string caption; // El texto para escribir
int speed; // Velocidad de escritura int speed{0}; // Velocidad de escritura
int writingCounter; // Temporizador de escritura para cada caracter int writingCounter{0}; // Temporizador de escritura para cada caracter
int index; // Posición del texto que se está escribiendo int index{0}; // Posición del texto que se está escribiendo
int lenght; // Longitud de la cadena a escribir int lenght{0}; // Longitud de la cadena a escribir
bool completed; // Indica si se ha escrito todo el texto bool completed{false}; // Indica si se ha escrito todo el texto
bool enabled; // Indica si el objeto está habilitado bool enabled{false}; // Indica si el objeto está habilitado
int enabledCounter; // Temporizador para deshabilitar el objeto int enabledCounter{0}; // Temporizador para deshabilitar el objeto
bool finished; // Indica si ya ha terminado bool finished{false}; // Indica si ya ha terminado
public: public:
// Constructor // Constructor
@@ -52,17 +52,17 @@ class Writer {
void setEnabled(bool value); void setEnabled(bool value);
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool IsEnabled(); [[nodiscard]] auto IsEnabled() const -> bool;
// Establece el valor de la variable // Establece el valor de la variable
void setEnabledCounter(int time); void setEnabledCounter(int time);
// Obtiene el valor de la variable // Obtiene el valor de la variable
int getEnabledCounter(); [[nodiscard]] auto getEnabledCounter() const -> int;
// Centra la cadena de texto a un punto X // Centra la cadena de texto a un punto X
void center(int x); void center(int x);
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool hasFinished(); [[nodiscard]] auto hasFinished() const -> bool;
}; };
+16 -18
View File
@@ -1,8 +1,8 @@
#include "core/resources/asset.h" #include "core/resources/asset.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <stddef.h> // for size_t
#include <cstddef> // for size_t
#include <iostream> // for basic_ostream, operator<<, cout, endl #include <iostream> // for basic_ostream, operator<<, cout, endl
#include "core/resources/resource_helper.h" #include "core/resources/resource_helper.h"
@@ -26,9 +26,7 @@ auto Asset::get() -> Asset * {
// Constructor // Constructor
Asset::Asset(const std::string &executablePath) Asset::Asset(const std::string &executablePath)
: longestName(0), : executablePath(executablePath.substr(0, executablePath.find_last_of("\\/"))) {
executablePath(executablePath.substr(0, executablePath.find_last_of("\\/"))),
verbose(true) {
} }
// Añade un elemento a la lista // Añade un elemento a la lista
@@ -44,10 +42,10 @@ void Asset::add(const std::string &file, enum assetType type, bool required, boo
} }
// Devuelve el fichero de un elemento de la lista a partir de una cadena // Devuelve el fichero de un elemento de la lista a partir de una cadena
std::string Asset::get(const std::string &text) { auto Asset::get(const std::string &text) -> std::string {
for (const auto &f : fileList) { for (const auto &f : fileList) {
const size_t lastIndex = f.file.find_last_of("/") + 1; const size_t lastIndex = f.file.find_last_of('/') + 1;
const std::string file = f.file.substr(lastIndex, std::string::npos); const std::string file = f.file.substr(lastIndex);
if (file == text) { if (file == text) {
return f.file; return f.file;
@@ -55,20 +53,20 @@ std::string Asset::get(const std::string &text) {
} }
if (verbose) { if (verbose) {
std::cout << "Warning: file " << text.c_str() << " not found" << std::endl; std::cout << "Warning: file " << text.c_str() << " not found" << '\n';
} }
return ""; return "";
} }
// Comprueba que existen todos los elementos // Comprueba que existen todos los elementos
bool Asset::check() { auto Asset::check() -> bool {
bool success = true; bool success = true;
if (verbose) { if (verbose) {
std::cout << "\n** Checking files" << std::endl; std::cout << "\n** Checking files" << '\n';
std::cout << "Executable path is: " << executablePath << std::endl; std::cout << "Executable path is: " << executablePath << '\n';
std::cout << "Sample filepath: " << fileList.back().file << std::endl; std::cout << "Sample filepath: " << fileList.back().file << '\n';
} }
// Comprueba la lista de ficheros clasificandolos por tipo // Comprueba la lista de ficheros clasificandolos por tipo
@@ -85,7 +83,7 @@ bool Asset::check() {
// Si hay ficheros de ese tipo, comprueba si existen // Si hay ficheros de ese tipo, comprueba si existen
if (any) { if (any) {
if (verbose) { if (verbose) {
std::cout << "\n>> " << getTypeName(type).c_str() << " FILES" << std::endl; std::cout << "\n>> " << getTypeName(type).c_str() << " FILES" << '\n';
} }
for (const auto &f : fileList) { for (const auto &f : fileList) {
@@ -100,10 +98,10 @@ bool Asset::check() {
if (verbose) { if (verbose) {
if (success) { if (success) {
std::cout << "\n** All files OK.\n" std::cout << "\n** All files OK.\n"
<< std::endl; << '\n';
} else { } else {
std::cout << "\n** A file is missing. Exiting.\n" std::cout << "\n** A file is missing. Exiting.\n"
<< std::endl; << '\n';
} }
} }
@@ -111,7 +109,7 @@ bool Asset::check() {
} }
// Comprueba que existe un fichero // Comprueba que existe un fichero
bool Asset::checkFile(const std::string &path) { auto Asset::checkFile(const std::string &path) const -> bool {
bool success = false; bool success = false;
std::string result = "ERROR"; std::string result = "ERROR";
@@ -138,14 +136,14 @@ bool Asset::checkFile(const std::string &path) {
std::cout.width(longestName + 2); std::cout.width(longestName + 2);
std::cout.fill('.'); std::cout.fill('.');
std::cout << filename + " "; std::cout << filename + " ";
std::cout << " [" + result + "]" << std::endl; std::cout << " [" + result + "]" << '\n';
} }
return success; return success;
} }
// Devuelve el nombre del tipo de recurso // Devuelve el nombre del tipo de recurso
std::string Asset::getTypeName(int type) { auto Asset::getTypeName(int type) -> std::string {
switch (type) { switch (type) {
case t_bitmap: case t_bitmap:
return "BITMAP"; return "BITMAP";
+9 -8
View File
@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <cstdint> // for uint8_t
#include <string> // for string, basic_string #include <string> // for string, basic_string
#include <vector> // for vector #include <vector> // for vector
enum assetType { enum assetType : std::uint8_t {
t_bitmap, t_bitmap,
t_music, t_music,
t_sound, t_sound,
@@ -28,16 +29,16 @@ class Asset {
private: private:
// Variables // Variables
int longestName; // Contiene la longitud del nombre de fichero mas largo int longestName{0}; // Contiene la longitud del nombre de fichero mas largo
std::vector<item_t> fileList; // Listado con todas las rutas a los ficheros std::vector<item_t> fileList; // Listado con todas las rutas a los ficheros
std::string executablePath; // Ruta al ejecutable std::string executablePath; // Ruta al ejecutable
bool verbose; // Indica si ha de mostrar información por pantalla bool verbose{true}; // Indica si ha de mostrar información por pantalla
// Comprueba que existe un fichero // Comprueba que existe un fichero
bool checkFile(const std::string &executablePath); [[nodiscard]] auto checkFile(const std::string &executablePath) const -> bool;
// Devuelve el nombre del tipo de recurso // Devuelve el nombre del tipo de recurso
std::string getTypeName(int type); static auto getTypeName(int type) -> std::string;
// Constructor privado (usar Asset::init) // Constructor privado (usar Asset::init)
explicit Asset(const std::string &path); explicit Asset(const std::string &path);
@@ -55,13 +56,13 @@ class Asset {
void add(const std::string &file, enum assetType type, bool required = true, bool absolute = false); void add(const std::string &file, enum assetType type, bool required = true, bool absolute = false);
// Devuelve un elemento de la lista a partir de una cadena // Devuelve un elemento de la lista a partir de una cadena
std::string get(const std::string &text); auto get(const std::string &text) -> std::string;
// Devuelve toda la lista de items registrados // Devuelve toda la lista de items registrados
const std::vector<item_t> &getAll() const { return fileList; } [[nodiscard]] auto getAll() const -> const std::vector<item_t> & { return fileList; }
// Comprueba que existen todos los elementos // Comprueba que existen todos los elementos
bool check(); auto check() -> bool;
// Establece si ha de mostrar texto por pantalla // Establece si ha de mostrar texto por pantalla
void setVerbose(bool value); void setVerbose(bool value);
+59 -31
View File
@@ -17,14 +17,16 @@
Resource *Resource::instance_ = nullptr; Resource *Resource::instance_ = nullptr;
static std::string basename(const std::string &path) { static auto basename(const std::string &path) -> std::string {
return path.substr(path.find_last_of("\\/") + 1); return path.substr(path.find_last_of("\\/") + 1);
} }
static std::string stem(const std::string &path) { static auto stem(const std::string &path) -> std::string {
std::string b = basename(path); std::string b = basename(path);
size_t dot = b.find_last_of('.'); size_t dot = b.find_last_of('.');
if (dot == std::string::npos) return b; if (dot == std::string::npos) {
return b;
}
return b.substr(0, dot); return b.substr(0, dot);
} }
@@ -40,7 +42,7 @@ void Resource::destroy() {
instance_ = nullptr; instance_ = nullptr;
} }
Resource *Resource::get() { auto Resource::get() -> Resource * {
return instance_; return instance_;
} }
@@ -48,19 +50,29 @@ Resource::Resource(SDL_Renderer *renderer)
: renderer_(renderer) {} : renderer_(renderer) {}
Resource::~Resource() { Resource::~Resource() {
for (auto &[name, m] : menus_) delete m; for (auto &[name, m] : menus_) {
delete m;
}
menus_.clear(); menus_.clear();
for (auto &[name, t] : texts_) delete t; for (auto &[name, t] : texts_) {
delete t;
}
texts_.clear(); texts_.clear();
for (auto &[name, t] : textures_) delete t; for (auto &[name, t] : textures_) {
delete t;
}
textures_.clear(); textures_.clear();
for (auto &[name, s] : sounds_) JA_DeleteSound(s); for (auto &[name, s] : sounds_) {
JA_DeleteSound(s);
}
sounds_.clear(); sounds_.clear();
for (auto &[name, m] : musics_) JA_DeleteMusic(m); for (auto &[name, m] : musics_) {
JA_DeleteMusic(m);
}
musics_.clear(); musics_.clear();
} }
@@ -74,7 +86,9 @@ void Resource::preloadAll() {
continue; continue;
} }
auto bytes = ResourceHelper::loadFile(it.file); auto bytes = ResourceHelper::loadFile(it.file);
if (bytes.empty()) continue; if (bytes.empty()) {
continue;
}
const std::string bname = basename(it.file); const std::string bname = basename(it.file);
@@ -86,12 +100,16 @@ void Resource::preloadAll() {
} }
case t_sound: { case t_sound: {
JA_Sound_t *s = JA_LoadSound(bytes.data(), (uint32_t)bytes.size()); JA_Sound_t *s = JA_LoadSound(bytes.data(), (uint32_t)bytes.size());
if (s) sounds_[bname] = s; if (s != nullptr) {
sounds_[bname] = s;
}
break; break;
} }
case t_music: { case t_music: {
JA_Music_t *m = JA_LoadMusic(bytes.data(), (Uint32)bytes.size()); JA_Music_t *m = JA_LoadMusic(bytes.data(), (Uint32)bytes.size());
if (m) musics_[bname] = m; if (m != nullptr) {
musics_[bname] = m;
}
break; break;
} }
case t_data: { case t_data: {
@@ -103,7 +121,9 @@ void Resource::preloadAll() {
while (std::getline(ss, line)) { while (std::getline(ss, line)) {
// Normalitza CRLF perquè loadFromVector compari línies amb literals // Normalitza CRLF perquè loadFromVector compari línies amb literals
// ("[animation]", "[/animation]") sense \r residual. // ("[animation]", "[/animation]") sense \r residual.
if (!line.empty() && line.back() == '\r') line.pop_back(); if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
lines.push_back(line); lines.push_back(line);
} }
animationLines_[bname] = std::move(lines); animationLines_[bname] = std::move(lines);
@@ -114,12 +134,8 @@ void Resource::preloadAll() {
} }
break; break;
} }
case t_font: case t_font: // Fonts: se emparejan en pass 2
// Fonts: se emparejan en pass 2 case t_lang: // Lenguaje: lo sigue leyendo la clase Lang via ResourceHelper
break;
case t_lang:
// Lenguaje: lo sigue leyendo la clase Lang a través de ResourceHelper
break;
default: default:
break; break;
} }
@@ -131,9 +147,13 @@ void Resource::preloadAll() {
std::unordered_map<std::string, std::vector<uint8_t>> fontPngs; std::unordered_map<std::string, std::vector<uint8_t>> fontPngs;
std::unordered_map<std::string, std::vector<uint8_t>> fontTxts; std::unordered_map<std::string, std::vector<uint8_t>> fontTxts;
for (const auto &it : items) { for (const auto &it : items) {
if (it.type != t_font) continue; if (it.type != t_font) {
continue;
}
auto bytes = ResourceHelper::loadFile(it.file); auto bytes = ResourceHelper::loadFile(it.file);
if (bytes.empty()) continue; if (bytes.empty()) {
continue;
}
const std::string s = stem(it.file); const std::string s = stem(it.file);
const std::string bname = basename(it.file); const std::string bname = basename(it.file);
if (bname.size() >= 4 && bname.substr(bname.size() - 4) == ".png") { if (bname.size() >= 4 && bname.substr(bname.size() - 4) == ".png") {
@@ -144,7 +164,9 @@ void Resource::preloadAll() {
} }
for (const auto &[s, png] : fontPngs) { for (const auto &[s, png] : fontPngs) {
auto itTxt = fontTxts.find(s); auto itTxt = fontTxts.find(s);
if (itTxt == fontTxts.end()) continue; if (itTxt == fontTxts.end()) {
continue;
}
Text *t = new Text(png, itTxt->second, renderer_); Text *t = new Text(png, itTxt->second, renderer_);
texts_[s] = t; texts_[s] = t;
} }
@@ -154,11 +176,17 @@ void Resource::preloadAll() {
// requiere que Menu se adapte a cargar desde ResourceHelper. Por ahora // requiere que Menu se adapte a cargar desde ResourceHelper. Por ahora
// lo dejamos así y será una migración del paso 7. // lo dejamos así y será una migración del paso 7.
for (const auto &it : items) { for (const auto &it : items) {
if (it.type != t_data) continue; if (it.type != t_data) {
continue;
}
const std::string bname = basename(it.file); const std::string bname = basename(it.file);
if (bname.size() < 4 || bname.substr(bname.size() - 4) != ".men") continue; if (bname.size() < 4 || bname.substr(bname.size() - 4) != ".men") {
continue;
}
auto bytes = ResourceHelper::loadFile(it.file); auto bytes = ResourceHelper::loadFile(it.file);
if (bytes.empty()) continue; if (bytes.empty()) {
continue;
}
Menu *m = new Menu(renderer_, ""); Menu *m = new Menu(renderer_, "");
m->loadFromBytes(bytes, bname); m->loadFromBytes(bytes, bname);
const std::string s = stem(it.file); const std::string s = stem(it.file);
@@ -166,7 +194,7 @@ void Resource::preloadAll() {
} }
} }
Texture *Resource::getTexture(const std::string &name) { auto Resource::getTexture(const std::string &name) -> Texture * {
auto it = textures_.find(name); auto it = textures_.find(name);
if (it == textures_.end()) { if (it == textures_.end()) {
std::cerr << "Resource::getTexture: missing " << name << '\n'; std::cerr << "Resource::getTexture: missing " << name << '\n';
@@ -175,7 +203,7 @@ Texture *Resource::getTexture(const std::string &name) {
return it->second; return it->second;
} }
JA_Sound_t *Resource::getSound(const std::string &name) { auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
auto it = sounds_.find(name); auto it = sounds_.find(name);
if (it == sounds_.end()) { if (it == sounds_.end()) {
std::cerr << "Resource::getSound: missing " << name << '\n'; std::cerr << "Resource::getSound: missing " << name << '\n';
@@ -184,7 +212,7 @@ JA_Sound_t *Resource::getSound(const std::string &name) {
return it->second; return it->second;
} }
JA_Music_t *Resource::getMusic(const std::string &name) { auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
auto it = musics_.find(name); auto it = musics_.find(name);
if (it == musics_.end()) { if (it == musics_.end()) {
std::cerr << "Resource::getMusic: missing " << name << '\n'; std::cerr << "Resource::getMusic: missing " << name << '\n';
@@ -193,7 +221,7 @@ JA_Music_t *Resource::getMusic(const std::string &name) {
return it->second; return it->second;
} }
std::vector<std::string> &Resource::getAnimationLines(const std::string &name) { auto Resource::getAnimationLines(const std::string &name) -> std::vector<std::string> & {
auto it = animationLines_.find(name); auto it = animationLines_.find(name);
if (it == animationLines_.end()) { if (it == animationLines_.end()) {
static std::vector<std::string> empty; static std::vector<std::string> empty;
@@ -203,7 +231,7 @@ std::vector<std::string> &Resource::getAnimationLines(const std::string &name) {
return it->second; return it->second;
} }
Text *Resource::getText(const std::string &name) { auto Resource::getText(const std::string &name) -> Text * {
auto it = texts_.find(name); auto it = texts_.find(name);
if (it == texts_.end()) { if (it == texts_.end()) {
std::cerr << "Resource::getText: missing " << name << '\n'; std::cerr << "Resource::getText: missing " << name << '\n';
@@ -212,7 +240,7 @@ Text *Resource::getText(const std::string &name) {
return it->second; return it->second;
} }
Menu *Resource::getMenu(const std::string &name) { auto Resource::getMenu(const std::string &name) -> Menu * {
auto it = menus_.find(name); auto it = menus_.find(name);
if (it == menus_.end()) { if (it == menus_.end()) {
std::cerr << "Resource::getMenu: missing " << name << '\n'; std::cerr << "Resource::getMenu: missing " << name << '\n';
+8 -8
View File
@@ -19,15 +19,15 @@ class Resource {
public: public:
static void init(SDL_Renderer *renderer); static void init(SDL_Renderer *renderer);
static void destroy(); static void destroy();
static Resource *get(); static auto get() -> Resource *;
Texture *getTexture(const std::string &name); auto getTexture(const std::string &name) -> Texture *;
JA_Sound_t *getSound(const std::string &name); auto getSound(const std::string &name) -> JA_Sound_t *;
JA_Music_t *getMusic(const std::string &name); auto getMusic(const std::string &name) -> JA_Music_t *;
std::vector<std::string> &getAnimationLines(const std::string &name); auto getAnimationLines(const std::string &name) -> std::vector<std::string> &;
Text *getText(const std::string &name); // name sin extensión: "smb2", "nokia2", ... auto getText(const std::string &name) -> Text *; // name sin extensión: "smb2", "nokia2", ...
Menu *getMenu(const std::string &name); // name sin extensión: "title", "options", ... auto getMenu(const std::string &name) -> Menu *; // name sin extensión: "title", "options", ...
const std::vector<uint8_t> &getDemoBytes() const { return demoBytes_; } auto getDemoBytes() const -> const std::vector<uint8_t> & { return demoBytes_; }
private: private:
explicit Resource(SDL_Renderer *renderer); explicit Resource(SDL_Renderer *renderer);
+5 -5
View File
@@ -10,7 +10,7 @@
namespace ResourceHelper { namespace ResourceHelper {
static bool resource_system_initialized = false; static bool resource_system_initialized = false;
bool initializeResourceSystem(const std::string& pack_file, bool enable_fallback) { auto initializeResourceSystem(const std::string& pack_file, bool enable_fallback) -> bool {
auto& loader = ResourceLoader::getInstance(); auto& loader = ResourceLoader::getInstance();
bool ok = loader.initialize(pack_file, enable_fallback); bool ok = loader.initialize(pack_file, enable_fallback);
resource_system_initialized = ok; resource_system_initialized = ok;
@@ -31,7 +31,7 @@ namespace ResourceHelper {
} }
} }
std::vector<uint8_t> loadFile(const std::string& filepath) { auto loadFile(const std::string& filepath) -> std::vector<uint8_t> {
if (resource_system_initialized && shouldUseResourcePack(filepath)) { if (resource_system_initialized && shouldUseResourcePack(filepath)) {
auto& loader = ResourceLoader::getInstance(); auto& loader = ResourceLoader::getInstance();
std::string pack_path = getPackPath(filepath); std::string pack_path = getPackPath(filepath);
@@ -58,14 +58,14 @@ namespace ResourceHelper {
return data; return data;
} }
bool shouldUseResourcePack(const std::string& filepath) { auto shouldUseResourcePack(const std::string& filepath) -> bool {
// Solo entran al pack los ficheros dentro de data/ // Solo entran al pack los ficheros dentro de data/
return filepath.find("data/") != std::string::npos; return filepath.find("data/") != std::string::npos;
} }
std::string getPackPath(const std::string& asset_path) { auto getPackPath(const std::string& asset_path) -> std::string {
std::string pack_path = asset_path; std::string pack_path = asset_path;
std::replace(pack_path.begin(), pack_path.end(), '\\', '/'); std::ranges::replace(pack_path, '\\', '/');
// Toma la última aparición de "data/" como prefijo a quitar // Toma la última aparición de "data/" como prefijo a quitar
size_t last_data = pack_path.rfind("data/"); size_t last_data = pack_path.rfind("data/");
+4 -4
View File
@@ -5,11 +5,11 @@
#include <vector> #include <vector>
namespace ResourceHelper { namespace ResourceHelper {
bool initializeResourceSystem(const std::string& pack_file = "resources.pack", bool enable_fallback = true); auto initializeResourceSystem(const std::string& pack_file = "resources.pack", bool enable_fallback = true) -> bool;
void shutdownResourceSystem(); void shutdownResourceSystem();
std::vector<uint8_t> loadFile(const std::string& filepath); auto loadFile(const std::string& filepath) -> std::vector<uint8_t>;
bool shouldUseResourcePack(const std::string& filepath); auto shouldUseResourcePack(const std::string& filepath) -> bool;
std::string getPackPath(const std::string& asset_path); auto getPackPath(const std::string& asset_path) -> std::string;
} // namespace ResourceHelper } // namespace ResourceHelper
+10 -12
View File
@@ -9,11 +9,9 @@
std::unique_ptr<ResourceLoader> ResourceLoader::instance = nullptr; std::unique_ptr<ResourceLoader> ResourceLoader::instance = nullptr;
ResourceLoader::ResourceLoader() ResourceLoader::ResourceLoader() = default;
: resource_pack_(nullptr),
fallback_to_files_(true) {}
ResourceLoader& ResourceLoader::getInstance() { auto ResourceLoader::getInstance() -> ResourceLoader& {
if (!instance) { if (!instance) {
instance = std::unique_ptr<ResourceLoader>(new ResourceLoader()); instance = std::unique_ptr<ResourceLoader>(new ResourceLoader());
} }
@@ -24,7 +22,7 @@ ResourceLoader::~ResourceLoader() {
shutdown(); shutdown();
} }
bool ResourceLoader::initialize(const std::string& pack_file, bool enable_fallback) { auto ResourceLoader::initialize(const std::string& pack_file, bool enable_fallback) -> bool {
shutdown(); shutdown();
fallback_to_files_ = enable_fallback; fallback_to_files_ = enable_fallback;
@@ -55,7 +53,7 @@ void ResourceLoader::shutdown() {
} }
} }
std::vector<uint8_t> ResourceLoader::loadResource(const std::string& filename) { auto ResourceLoader::loadResource(const std::string& filename) -> std::vector<uint8_t> {
if ((resource_pack_ != nullptr) && resource_pack_->hasResource(filename)) { if ((resource_pack_ != nullptr) && resource_pack_->hasResource(filename)) {
return resource_pack_->getResource(filename); return resource_pack_->getResource(filename);
} }
@@ -68,7 +66,7 @@ std::vector<uint8_t> ResourceLoader::loadResource(const std::string& filename) {
return {}; return {};
} }
bool ResourceLoader::resourceExists(const std::string& filename) { auto ResourceLoader::resourceExists(const std::string& filename) -> bool {
if ((resource_pack_ != nullptr) && resource_pack_->hasResource(filename)) { if ((resource_pack_ != nullptr) && resource_pack_->hasResource(filename)) {
return true; return true;
} }
@@ -81,7 +79,7 @@ bool ResourceLoader::resourceExists(const std::string& filename) {
return false; return false;
} }
std::vector<uint8_t> ResourceLoader::loadFromFile(const std::string& filename) { auto ResourceLoader::loadFromFile(const std::string& filename) -> std::vector<uint8_t> {
std::string full_path = getDataPath(filename); std::string full_path = getDataPath(filename);
std::ifstream file(full_path, std::ios::binary | std::ios::ate); std::ifstream file(full_path, std::ios::binary | std::ios::ate);
@@ -102,18 +100,18 @@ std::vector<uint8_t> ResourceLoader::loadFromFile(const std::string& filename) {
return data; return data;
} }
std::string ResourceLoader::getDataPath(const std::string& filename) { auto ResourceLoader::getDataPath(const std::string& filename) -> std::string {
return "data/" + filename; return "data/" + filename;
} }
size_t ResourceLoader::getLoadedResourceCount() const { auto ResourceLoader::getLoadedResourceCount() const -> size_t {
if (resource_pack_ != nullptr) { if (resource_pack_ != nullptr) {
return resource_pack_->getResourceCount(); return resource_pack_->getResourceCount();
} }
return 0; return 0;
} }
std::vector<std::string> ResourceLoader::getAvailableResources() const { auto ResourceLoader::getAvailableResources() const -> std::vector<std::string> {
if (resource_pack_ != nullptr) { if (resource_pack_ != nullptr) {
return resource_pack_->getResourceList(); return resource_pack_->getResourceList();
} }
@@ -123,7 +121,7 @@ std::vector<std::string> ResourceLoader::getAvailableResources() const {
for (const auto& entry : std::filesystem::recursive_directory_iterator("data")) { for (const auto& entry : std::filesystem::recursive_directory_iterator("data")) {
if (entry.is_regular_file()) { if (entry.is_regular_file()) {
std::string filename = std::filesystem::relative(entry.path(), "data").string(); std::string filename = std::filesystem::relative(entry.path(), "data").string();
std::replace(filename.begin(), filename.end(), '\\', '/'); std::ranges::replace(filename, '\\', '/');
result.push_back(filename); result.push_back(filename);
} }
} }
+11 -11
View File
@@ -11,29 +11,29 @@ class ResourcePack;
class ResourceLoader { class ResourceLoader {
private: private:
static std::unique_ptr<ResourceLoader> instance; static std::unique_ptr<ResourceLoader> instance;
ResourcePack* resource_pack_; ResourcePack* resource_pack_{nullptr};
std::string pack_path_; std::string pack_path_;
bool fallback_to_files_; bool fallback_to_files_{true};
ResourceLoader(); ResourceLoader();
public: public:
static ResourceLoader& getInstance(); static auto getInstance() -> ResourceLoader&;
~ResourceLoader(); ~ResourceLoader();
bool initialize(const std::string& pack_file, bool enable_fallback = true); auto initialize(const std::string& pack_file, bool enable_fallback = true) -> bool;
void shutdown(); void shutdown();
std::vector<uint8_t> loadResource(const std::string& filename); auto loadResource(const std::string& filename) -> std::vector<uint8_t>;
bool resourceExists(const std::string& filename); auto resourceExists(const std::string& filename) -> bool;
void setFallbackToFiles(bool enable) { fallback_to_files_ = enable; } void setFallbackToFiles(bool enable) { fallback_to_files_ = enable; }
bool getFallbackToFiles() const { return fallback_to_files_; } [[nodiscard]] auto getFallbackToFiles() const -> bool { return fallback_to_files_; }
size_t getLoadedResourceCount() const; [[nodiscard]] auto getLoadedResourceCount() const -> size_t;
std::vector<std::string> getAvailableResources() const; [[nodiscard]] auto getAvailableResources() const -> std::vector<std::string>;
private: private:
static std::vector<uint8_t> loadFromFile(const std::string& filename); static auto loadFromFile(const std::string& filename) -> std::vector<uint8_t>;
static std::string getDataPath(const std::string& filename); static auto getDataPath(const std::string& filename) -> std::string;
}; };
+16 -15
View File
@@ -10,19 +10,20 @@
const std::string ResourcePack::DEFAULT_ENCRYPT_KEY = "CCRS_RESOURCES__2026"; const std::string ResourcePack::DEFAULT_ENCRYPT_KEY = "CCRS_RESOURCES__2026";
ResourcePack::ResourcePack() ResourcePack::ResourcePack() = default;
: loaded_(false) {}
ResourcePack::~ResourcePack() { ResourcePack::~ResourcePack() {
clear(); clear();
} }
uint32_t ResourcePack::calculateChecksum(const std::vector<uint8_t>& data) { auto ResourcePack::calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t {
return std::accumulate(data.begin(), data.end(), uint32_t(0x12345678), [](uint32_t acc, uint8_t b) { return ((acc << 5) + acc) + b; }); return std::accumulate(data.begin(), data.end(), uint32_t(0x12345678), [](uint32_t acc, uint8_t b) { return ((acc << 5) + acc) + b; });
} }
void ResourcePack::encryptData(std::vector<uint8_t>& data, const std::string& key) { void ResourcePack::encryptData(std::vector<uint8_t>& data, const std::string& key) {
if (key.empty()) return; if (key.empty()) {
return;
}
for (size_t i = 0; i < data.size(); ++i) { for (size_t i = 0; i < data.size(); ++i) {
data[i] ^= key[i % key.length()]; data[i] ^= key[i % key.length()];
} }
@@ -32,7 +33,7 @@ void ResourcePack::decryptData(std::vector<uint8_t>& data, const std::string& ke
encryptData(data, key); encryptData(data, key);
} }
bool ResourcePack::loadPack(const std::string& pack_file) { auto ResourcePack::loadPack(const std::string& pack_file) -> bool {
std::ifstream file(pack_file, std::ios::binary); std::ifstream file(pack_file, std::ios::binary);
if (!file) { if (!file) {
std::cerr << "Error: Could not open pack file: " << pack_file << '\n'; std::cerr << "Error: Could not open pack file: " << pack_file << '\n';
@@ -87,7 +88,7 @@ bool ResourcePack::loadPack(const std::string& pack_file) {
return true; return true;
} }
bool ResourcePack::savePack(const std::string& pack_file) { auto ResourcePack::savePack(const std::string& pack_file) -> bool {
std::ofstream file(pack_file, std::ios::binary); std::ofstream file(pack_file, std::ios::binary);
if (!file) { if (!file) {
std::cerr << "Error: Could not create pack file: " << pack_file << '\n'; std::cerr << "Error: Could not create pack file: " << pack_file << '\n';
@@ -99,11 +100,11 @@ bool ResourcePack::savePack(const std::string& pack_file) {
uint32_t version = 1; uint32_t version = 1;
file.write(reinterpret_cast<const char*>(&version), sizeof(version)); file.write(reinterpret_cast<const char*>(&version), sizeof(version));
uint32_t resource_count = static_cast<uint32_t>(resources_.size()); auto resource_count = static_cast<uint32_t>(resources_.size());
file.write(reinterpret_cast<const char*>(&resource_count), sizeof(resource_count)); file.write(reinterpret_cast<const char*>(&resource_count), sizeof(resource_count));
for (const auto& [filename, entry] : resources_) { for (const auto& [filename, entry] : resources_) {
uint32_t filename_length = static_cast<uint32_t>(filename.length()); auto filename_length = static_cast<uint32_t>(filename.length());
file.write(reinterpret_cast<const char*>(&filename_length), sizeof(filename_length)); file.write(reinterpret_cast<const char*>(&filename_length), sizeof(filename_length));
file.write(filename.c_str(), filename_length); file.write(filename.c_str(), filename_length);
@@ -122,7 +123,7 @@ bool ResourcePack::savePack(const std::string& pack_file) {
return true; return true;
} }
bool ResourcePack::addFile(const std::string& filename, const std::string& filepath) { auto ResourcePack::addFile(const std::string& filename, const std::string& filepath) -> bool {
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 << "Error: Could not open file: " << filepath << '\n'; std::cerr << "Error: Could not open file: " << filepath << '\n';
@@ -150,7 +151,7 @@ bool ResourcePack::addFile(const std::string& filename, const std::string& filep
return true; return true;
} }
bool ResourcePack::addDirectory(const std::string& directory) { auto ResourcePack::addDirectory(const std::string& directory) -> bool {
if (!std::filesystem::exists(directory)) { if (!std::filesystem::exists(directory)) {
std::cerr << "Error: Directory does not exist: " << directory << '\n'; std::cerr << "Error: Directory does not exist: " << directory << '\n';
return false; return false;
@@ -162,7 +163,7 @@ bool ResourcePack::addDirectory(const std::string& directory) {
std::string filepath = entry.path().string(); std::string filepath = entry.path().string();
std::string filename = std::filesystem::relative(entry.path(), directory).string(); std::string filename = std::filesystem::relative(entry.path(), directory).string();
std::replace(filename.begin(), filename.end(), '\\', '/'); std::ranges::replace(filename, '\\', '/');
if (!addFile(filename, filepath)) { if (!addFile(filename, filepath)) {
return false; return false;
@@ -173,7 +174,7 @@ bool ResourcePack::addDirectory(const std::string& directory) {
return true; return true;
} }
std::vector<uint8_t> ResourcePack::getResource(const std::string& filename) { auto ResourcePack::getResource(const std::string& filename) -> std::vector<uint8_t> {
auto it = resources_.find(filename); auto it = resources_.find(filename);
if (it == resources_.end()) { if (it == resources_.end()) {
std::cerr << "Error: Resource not found: " << filename << '\n'; std::cerr << "Error: Resource not found: " << filename << '\n';
@@ -197,7 +198,7 @@ std::vector<uint8_t> ResourcePack::getResource(const std::string& filename) {
return result; return result;
} }
bool ResourcePack::hasResource(const std::string& filename) const { auto ResourcePack::hasResource(const std::string& filename) const -> bool {
return resources_.find(filename) != resources_.end(); return resources_.find(filename) != resources_.end();
} }
@@ -207,11 +208,11 @@ void ResourcePack::clear() {
loaded_ = false; loaded_ = false;
} }
size_t ResourcePack::getResourceCount() const { auto ResourcePack::getResourceCount() const -> size_t {
return resources_.size(); return resources_.size();
} }
std::vector<std::string> ResourcePack::getResourceList() const { auto ResourcePack::getResourceList() const -> std::vector<std::string> {
std::vector<std::string> result; std::vector<std::string> result;
result.reserve(resources_.size()); result.reserve(resources_.size());
for (const auto& [filename, entry] : resources_) { for (const auto& [filename, entry] : resources_) {
+10 -10
View File
@@ -17,9 +17,9 @@ class ResourcePack {
private: private:
std::unordered_map<std::string, ResourceEntry> resources_; std::unordered_map<std::string, ResourceEntry> resources_;
std::vector<uint8_t> data_; std::vector<uint8_t> data_;
bool loaded_; bool loaded_{false};
static uint32_t calculateChecksum(const std::vector<uint8_t>& data); static auto calculateChecksum(const std::vector<uint8_t>& data) -> uint32_t;
static void encryptData(std::vector<uint8_t>& data, const std::string& key); static void encryptData(std::vector<uint8_t>& data, const std::string& key);
static void decryptData(std::vector<uint8_t>& data, const std::string& key); static void decryptData(std::vector<uint8_t>& data, const std::string& key);
@@ -27,18 +27,18 @@ class ResourcePack {
ResourcePack(); ResourcePack();
~ResourcePack(); ~ResourcePack();
bool loadPack(const std::string& pack_file); auto loadPack(const std::string& pack_file) -> bool;
bool savePack(const std::string& pack_file); auto savePack(const std::string& pack_file) -> bool;
bool addFile(const std::string& filename, const std::string& filepath); auto addFile(const std::string& filename, const std::string& filepath) -> bool;
bool addDirectory(const std::string& directory); auto addDirectory(const std::string& directory) -> bool;
std::vector<uint8_t> getResource(const std::string& filename); auto getResource(const std::string& filename) -> std::vector<uint8_t>;
bool hasResource(const std::string& filename) const; auto hasResource(const std::string& filename) const -> bool;
void clear(); void clear();
size_t getResourceCount() const; auto getResourceCount() const -> size_t;
std::vector<std::string> getResourceList() const; auto getResourceList() const -> std::vector<std::string>;
static const std::string DEFAULT_ENCRYPT_KEY; static const std::string DEFAULT_ENCRYPT_KEY;
}; };
+11 -11
View File
@@ -96,16 +96,16 @@ class Menu {
std::string font_txt; std::string font_txt;
// Carga la configuración del menu desde un archivo de texto // Carga la configuración del menu desde un archivo de texto
bool load(const std::string &file_path); auto load(const std::string &file_path) -> bool;
// Parser compartido (recibe cualquier istream) // Parser compartido (recibe cualquier istream)
bool parseFromStream(std::istream &file, const std::string &filename); auto parseFromStream(std::istream &file, const std::string &filename) -> bool;
// Asigna variables a partir de dos cadenas // Asigna variables a partir de dos cadenas
bool setVars(const std::string &var, const std::string &value); auto setVars(const std::string &var, const std::string &value) -> bool;
// Asigna variables a partir de dos cadenas // Asigna variables a partir de dos cadenas
bool setItem(item_t *item, const std::string &var, const std::string &value); auto setItem(item_t *item, const std::string &var, const std::string &value) -> bool;
// Actualiza el menu para recolocarlo correctamente y establecer el tamaño // Actualiza el menu para recolocarlo correctamente y establecer el tamaño
void reorganize(); void reorganize();
@@ -120,22 +120,22 @@ class Menu {
void updateSelector(); void updateSelector();
// Obtiene la anchura del elemento más ancho del menu // Obtiene la anchura del elemento más ancho del menu
int getWidestItem(); auto getWidestItem() -> int;
// Gestiona la entrada de teclado y mando durante el menu // Gestiona la entrada de teclado y mando durante el menu
void checkMenuInput(Menu *menu); void checkMenuInput(Menu *menu);
// Calcula el ancho del menu // Calcula el ancho del menu
int findWidth(); auto findWidth() -> int;
// Calcula el alto del menu // Calcula el alto del menu
int findHeight(); auto findHeight() -> int;
// Recoloca los elementos del menu en el eje Y // Recoloca los elementos del menu en el eje Y
void replaceElementsOnY(); void replaceElementsOnY();
// Calcula la altura del selector // Calcula la altura del selector
int getSelectorHeight(int value); auto getSelectorHeight(int value) -> int;
// Calcula los colores del selector para el degradado // Calcula los colores del selector para el degradado
void setSelectorItemColors(); void setSelectorItemColors();
@@ -148,16 +148,16 @@ class Menu {
~Menu(); ~Menu();
// Carga el menu desde bytes en memoria // Carga el menu desde bytes en memoria
bool loadFromBytes(const std::vector<uint8_t> &bytes, const std::string &nameForLogs = ""); auto loadFromBytes(const std::vector<uint8_t> &bytes, const std::string &nameForLogs = "") -> bool;
// Carga los ficheros de audio // Carga los ficheros de audio
void loadAudioFile(const std::string &file, int sound); void loadAudioFile(const std::string &file, int sound);
// Obtiene el nombre del menu // Obtiene el nombre del menu
const std::string &getName() const; [[nodiscard]] auto getName() const -> const std::string &;
// Obtiene el valor de la variable // Obtiene el valor de la variable
int getItemSelected(); auto getItemSelected() -> int;
// Deja el menu apuntando al primer elemento // Deja el menu apuntando al primer elemento
void reset(); void reset();