Merge branch 'tidy-cleanup'
This commit is contained in:
+31
-30
@@ -8,6 +8,7 @@
|
||||
// Implementación de stb_vorbis (debe estar ANTES de incluir jail_audio.hpp).
|
||||
// clang-format off
|
||||
#undef STB_VORBIS_HEADER_ONLY
|
||||
// NOLINTNEXTLINE(bugprone-suspicious-include) — stb_vorbis és single-file: el TU principal inclou el .c per portar la implementació.
|
||||
#include "external/stb_vorbis.c"
|
||||
// stb_vorbis.c filtra les macros L, C i R (i PLAYBACK_*) al TU. Les netegem
|
||||
// perquè xocarien amb noms de paràmetres de plantilla en altres headers.
|
||||
@@ -43,15 +44,15 @@ Audio::Audio() { initSDLAudio(); }
|
||||
|
||||
// Destructor
|
||||
Audio::~Audio() {
|
||||
JA_Quit();
|
||||
Ja::quit();
|
||||
}
|
||||
|
||||
// Método principal
|
||||
void Audio::update() {
|
||||
JA_Update();
|
||||
Ja::update();
|
||||
|
||||
// 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::MusicState::PLAYING) {
|
||||
instance->music_.state = MusicState::STOPPED;
|
||||
}
|
||||
}
|
||||
@@ -65,18 +66,18 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa
|
||||
return;
|
||||
}
|
||||
|
||||
if (!music_enabled_) return;
|
||||
if (!music_enabled_) { return; }
|
||||
|
||||
auto* resource = AudioResource::getMusic(name);
|
||||
if (resource == nullptr) return;
|
||||
if (resource == nullptr) { return; }
|
||||
|
||||
if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) {
|
||||
JA_CrossfadeMusic(resource, crossfade_ms, loop);
|
||||
Ja::crossfadeMusic(resource, crossfade_ms, loop);
|
||||
} else {
|
||||
if (music_.state == MusicState::PLAYING) {
|
||||
JA_StopMusic();
|
||||
Ja::stopMusic();
|
||||
}
|
||||
JA_PlayMusic(resource, loop);
|
||||
Ja::playMusic(resource, loop);
|
||||
}
|
||||
|
||||
music_.name = name;
|
||||
@@ -85,16 +86,16 @@ void Audio::playMusic(const std::string& name, const int loop, const int crossfa
|
||||
}
|
||||
|
||||
// Reproduce la música por puntero (con crossfade opcional)
|
||||
void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms) {
|
||||
if (!music_enabled_ || music == nullptr) return;
|
||||
void Audio::playMusic(Ja::Music* music, const int loop, const int crossfade_ms) {
|
||||
if (!music_enabled_ || music == nullptr) { return; }
|
||||
|
||||
if (crossfade_ms > 0 && music_.state == MusicState::PLAYING) {
|
||||
JA_CrossfadeMusic(music, crossfade_ms, loop);
|
||||
Ja::crossfadeMusic(music, crossfade_ms, loop);
|
||||
} else {
|
||||
if (music_.state == MusicState::PLAYING) {
|
||||
JA_StopMusic();
|
||||
Ja::stopMusic();
|
||||
}
|
||||
JA_PlayMusic(music, loop);
|
||||
Ja::playMusic(music, loop);
|
||||
}
|
||||
|
||||
music_.name.clear(); // nom desconegut quan es passa per punter
|
||||
@@ -105,7 +106,7 @@ void Audio::playMusic(JA_Music_t* music, const int loop, const int crossfade_ms)
|
||||
// Pausa la música
|
||||
void Audio::pauseMusic() {
|
||||
if (music_enabled_ && music_.state == MusicState::PLAYING) {
|
||||
JA_PauseMusic();
|
||||
Ja::pauseMusic();
|
||||
music_.state = MusicState::PAUSED;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +114,7 @@ void Audio::pauseMusic() {
|
||||
// Continua la música pausada
|
||||
void Audio::resumeMusic() {
|
||||
if (music_enabled_ && music_.state == MusicState::PAUSED) {
|
||||
JA_ResumeMusic();
|
||||
Ja::resumeMusic();
|
||||
music_.state = MusicState::PLAYING;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +122,7 @@ void Audio::resumeMusic() {
|
||||
// Detiene la música
|
||||
void Audio::stopMusic() {
|
||||
if (music_enabled_) {
|
||||
JA_StopMusic();
|
||||
Ja::stopMusic();
|
||||
music_.state = MusicState::STOPPED;
|
||||
}
|
||||
}
|
||||
@@ -129,42 +130,42 @@ void Audio::stopMusic() {
|
||||
// Reproduce un sonido por nombre
|
||||
void Audio::playSound(const std::string& name, Group group) const {
|
||||
if (sound_enabled_) {
|
||||
JA_PlaySound(AudioResource::getSound(name), 0, static_cast<int>(group));
|
||||
Ja::playSound(AudioResource::getSound(name), 0, static_cast<int>(group));
|
||||
}
|
||||
}
|
||||
|
||||
// Reproduce un sonido por puntero directo
|
||||
void Audio::playSound(JA_Sound_t* sound, Group group) const {
|
||||
void Audio::playSound(Ja::Sound* sound, Group group) const {
|
||||
if (sound_enabled_ && sound != nullptr) {
|
||||
JA_PlaySound(sound, 0, static_cast<int>(group));
|
||||
Ja::playSound(sound, 0, static_cast<int>(group));
|
||||
}
|
||||
}
|
||||
|
||||
// Detiene todos los sonidos
|
||||
void Audio::stopAllSounds() const {
|
||||
if (sound_enabled_) {
|
||||
JA_StopChannel(-1);
|
||||
Ja::stopChannel(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// Realiza un fundido de salida de la música
|
||||
void Audio::fadeOutMusic(int milliseconds) const {
|
||||
if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) {
|
||||
JA_FadeOutMusic(milliseconds);
|
||||
Ja::fadeOutMusic(milliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
// Consulta directamente el estado real de la música en jailaudio
|
||||
auto Audio::getRealMusicState() -> MusicState {
|
||||
JA_Music_state ja_state = JA_GetMusicState();
|
||||
Ja::MusicState ja_state = Ja::getMusicState();
|
||||
switch (ja_state) {
|
||||
case JA_MUSIC_PLAYING:
|
||||
case Ja::MusicState::PLAYING:
|
||||
return MusicState::PLAYING;
|
||||
case JA_MUSIC_PAUSED:
|
||||
case Ja::MusicState::PAUSED:
|
||||
return MusicState::PAUSED;
|
||||
case JA_MUSIC_STOPPED:
|
||||
case JA_MUSIC_INVALID:
|
||||
case JA_MUSIC_DISABLED:
|
||||
case Ja::MusicState::STOPPED:
|
||||
case Ja::MusicState::INVALID:
|
||||
case Ja::MusicState::DISABLED:
|
||||
default:
|
||||
return MusicState::STOPPED;
|
||||
}
|
||||
@@ -175,7 +176,7 @@ void Audio::setSoundVolume(float sound_volume, Group group) const {
|
||||
if (sound_enabled_) {
|
||||
sound_volume = std::clamp(sound_volume, MIN_VOLUME, MAX_VOLUME);
|
||||
const float CONVERTED_VOLUME = sound_volume * Options::audio.volume;
|
||||
JA_SetSoundVolume(CONVERTED_VOLUME, static_cast<int>(group));
|
||||
Ja::setSoundVolume(CONVERTED_VOLUME, static_cast<int>(group));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +185,7 @@ void Audio::setMusicVolume(float music_volume) const {
|
||||
if (music_enabled_) {
|
||||
music_volume = std::clamp(music_volume, MIN_VOLUME, MAX_VOLUME);
|
||||
const float CONVERTED_VOLUME = music_volume * Options::audio.volume;
|
||||
JA_SetMusicVolume(CONVERTED_VOLUME);
|
||||
Ja::setMusicVolume(CONVERTED_VOLUME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +207,7 @@ void Audio::initSDLAudio() {
|
||||
if (!SDL_Init(SDL_INIT_AUDIO)) {
|
||||
std::cout << "SDL_AUDIO could not initialize! SDL Error: " << SDL_GetError() << '\n';
|
||||
} else {
|
||||
JA_Init(FREQUENCY, SDL_AUDIO_S16LE, 2);
|
||||
Ja::init(FREQUENCY, SDL_AUDIO_S16LE, 2);
|
||||
enable(Options::audio.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-12
@@ -1,8 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath> // Para std::lround
|
||||
#include <cstdint> // Para int8_t, uint8_t
|
||||
#include <string> // Para string
|
||||
#include <utility> // Para move
|
||||
|
||||
namespace Ja {
|
||||
struct Music;
|
||||
struct Sound;
|
||||
} // namespace Ja
|
||||
|
||||
// --- Clase Audio: gestor de audio (singleton) ---
|
||||
// Implementació canònica, byte-idèntica entre projectes.
|
||||
@@ -41,17 +46,17 @@ class Audio {
|
||||
static void update(); // Actualización del sistema de audio
|
||||
|
||||
// --- Control de música ---
|
||||
void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproducir música por nombre (con crossfade opcional)
|
||||
void playMusic(struct JA_Music_t* music, int loop = -1, int crossfade_ms = 0); // Reproducir música por puntero (con crossfade opcional)
|
||||
void pauseMusic(); // Pausar reproducción de música
|
||||
void resumeMusic(); // Continua la música pausada
|
||||
void stopMusic(); // Detener completamente la música
|
||||
void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música
|
||||
void playMusic(const std::string& name, int loop = -1, int crossfade_ms = 0); // Reproducir música por nombre (con crossfade opcional)
|
||||
void playMusic(Ja::Music* music, int loop = -1, int crossfade_ms = 0); // Reproducir música por puntero (con crossfade opcional)
|
||||
void pauseMusic(); // Pausar reproducción de música
|
||||
void resumeMusic(); // Continua la música pausada
|
||||
void stopMusic(); // Detener completamente la música
|
||||
void fadeOutMusic(int milliseconds) const; // Fundido de salida de la música
|
||||
|
||||
// --- Control de sonidos ---
|
||||
void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre
|
||||
void playSound(struct JA_Sound_t* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero
|
||||
void stopAllSounds() const; // Detener todos los sonidos
|
||||
void playSound(const std::string& name, Group group = Group::GAME) const; // Reproducir sonido puntual por nombre
|
||||
void playSound(Ja::Sound* sound, Group group = Group::GAME) const; // Reproducir sonido puntual por puntero
|
||||
void stopAllSounds() const; // Detener todos los sonidos
|
||||
|
||||
// --- Control de volumen (API interna: float 0.0..1.0) ---
|
||||
void setSoundVolume(float volume, Group group = Group::ALL) const; // Ajustar volumen de efectos
|
||||
@@ -59,8 +64,8 @@ class Audio {
|
||||
|
||||
// --- Helpers de conversió per a la capa de presentació ---
|
||||
// UI (menús, notificacions) manega enters 0..100; internament viu float 0..1.
|
||||
static constexpr auto toPercent(float volume) -> int {
|
||||
return static_cast<int>(volume * 100.0F + 0.5F);
|
||||
static auto toPercent(float volume) -> int {
|
||||
return static_cast<int>(std::lround(volume * 100.0F));
|
||||
}
|
||||
static constexpr auto fromPercent(int percent) -> float {
|
||||
return static_cast<float>(percent) / 100.0F;
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
#include "core/resources/resource.hpp"
|
||||
|
||||
namespace AudioResource {
|
||||
JA_Music_t* getMusic(const std::string& name) {
|
||||
auto getMusic(const std::string& name) -> Ja::Music* {
|
||||
return Resource::get()->getMusic(name);
|
||||
}
|
||||
|
||||
JA_Sound_t* getSound(const std::string& name) {
|
||||
auto getSound(const std::string& name) -> Ja::Sound* {
|
||||
return Resource::get()->getSound(name);
|
||||
}
|
||||
} // namespace AudioResource
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
// --- Audio Resource Adapter ---
|
||||
// Aquest fitxer exposa una interfície comuna a Audio per obtenir JA_Music_t* /
|
||||
// JA_Sound_t* per nom. Cada projecte la implementa en audio_adapter.cpp
|
||||
// Aquest fitxer exposa una interfície comuna a Audio per obtenir Ja::Music* /
|
||||
// Ja::Sound* per nom. Cada projecte la implementa en audio_adapter.cpp
|
||||
// delegant al seu singleton de recursos (Resource::get(), Resource::Cache::get(),
|
||||
// etc.). Això permet que audio.hpp/audio.cpp siguin idèntics entre projectes.
|
||||
|
||||
#include <string> // Para string
|
||||
|
||||
struct JA_Music_t;
|
||||
struct JA_Sound_t;
|
||||
namespace Ja {
|
||||
struct Music;
|
||||
struct Sound;
|
||||
} // namespace Ja
|
||||
|
||||
namespace AudioResource {
|
||||
JA_Music_t* getMusic(const std::string& name);
|
||||
JA_Sound_t* getSound(const std::string& name);
|
||||
auto getMusic(const std::string& name) -> Ja::Music*;
|
||||
auto getSound(const std::string& name) -> Ja::Sound*;
|
||||
} // namespace AudioResource
|
||||
|
||||
+595
-575
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@
|
||||
#include <memory> // Para unique_ptr, allocator, shared_ptr, operator==, make_unique
|
||||
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/input/input_types.hpp" // Para InputAction
|
||||
#include "core/locale/lang.hpp" // Para getText
|
||||
#include "core/resources/resource.hpp" // Para Resource
|
||||
#include "game/options.hpp" // Para Gamepad
|
||||
@@ -17,9 +16,9 @@ DefineButtons::DefineButtons()
|
||||
: input_(Input::get()) {
|
||||
clearButtons();
|
||||
|
||||
const auto gamepads = input_->getGamepads();
|
||||
controller_names_.reserve(gamepads.size());
|
||||
std::ranges::transform(gamepads, std::back_inserter(controller_names_), Input::getControllerName);
|
||||
const auto GAMEPADS = input_->getGamepads();
|
||||
controller_names_.reserve(GAMEPADS.size());
|
||||
std::ranges::transform(GAMEPADS, std::back_inserter(controller_names_), Input::getControllerName);
|
||||
|
||||
// Crear la ventana de mensaje
|
||||
WindowMessage::Config config(param.service_menu.window_message);
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
#include <algorithm> // Para __any_of_fn, any_of
|
||||
#include <functional> // Para function
|
||||
#include <iterator> // Para pair
|
||||
#include <string> // Para basic_string, operator+, allocator, char_traits, string, to_string
|
||||
#include <utility> // Para pair
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/input/input_types.hpp" // Para InputAction
|
||||
#include "core/locale/lang.hpp" // Para getText, getLangFile, getLangName, getNextLangCode, loadFromFile
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/system/section.hpp" // Para Name, name, Options, options, AttractMode, attract_mode
|
||||
@@ -84,12 +82,12 @@ namespace GlobalInputs {
|
||||
void nextPreset() {
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
Screen::nextCrtPiPreset();
|
||||
const std::string name = Options::crtpi_presets.empty() ? "" : Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset)).name;
|
||||
Notifier::get()->show({"CrtPi: " + name});
|
||||
const std::string NAME = Options::crtpi_presets.empty() ? "" : Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset)).name;
|
||||
Notifier::get()->show({"CrtPi: " + NAME});
|
||||
} else {
|
||||
Screen::nextPostFXPreset();
|
||||
const std::string name = Options::postfx_presets.empty() ? "" : Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset)).name;
|
||||
Notifier::get()->show({"PostFX: " + name});
|
||||
const std::string NAME = Options::postfx_presets.empty() ? "" : Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset)).name;
|
||||
Notifier::get()->show({"PostFX: " + NAME});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,15 +157,15 @@ auto Input::getNumGamepads() const -> int { return gamepads_.size(); }
|
||||
|
||||
// Obtiene el gamepad a partir de un event.id
|
||||
auto Input::getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Input::Gamepad> {
|
||||
const auto it = std::ranges::find_if(gamepads_,
|
||||
const auto IT = std::ranges::find_if(gamepads_,
|
||||
[id](const auto& gamepad) { return gamepad->instance_id == id; });
|
||||
return it != gamepads_.end() ? *it : nullptr;
|
||||
return IT != gamepads_.end() ? *IT : nullptr;
|
||||
}
|
||||
|
||||
auto Input::getGamepadByName(const std::string& name) const -> std::shared_ptr<Input::Gamepad> {
|
||||
const auto it = std::ranges::find_if(gamepads_,
|
||||
const auto IT = std::ranges::find_if(gamepads_,
|
||||
[&name](const auto& gamepad) { return gamepad && gamepad->name == name; });
|
||||
return it != gamepads_.end() ? *it : nullptr;
|
||||
return IT != gamepads_.end() ? *IT : nullptr;
|
||||
}
|
||||
|
||||
// Obtiene el SDL_GamepadButton asignado a un action
|
||||
@@ -360,8 +360,9 @@ auto Input::handleEvent(const SDL_Event& event) -> std::string {
|
||||
return addGamepad(event.gdevice.which);
|
||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||
return removeGamepad(event.gdevice.which);
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Input::addGamepad(int device_index) -> std::string {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string, basic_string
|
||||
#include <unordered_map> // Para unordered_map
|
||||
#include <utility> // Para pair
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/input/gamepad_config_manager.hpp" // for GamepadConfig (ptr only), GamepadConfigs
|
||||
@@ -109,8 +108,8 @@ class Input {
|
||||
// Evita nombres como "Retroid Controller (vendor: 1001) ..." en las notificaciones.
|
||||
static auto trimName(const char* raw) -> std::string {
|
||||
std::string s(raw != nullptr ? raw : "");
|
||||
const auto pos = s.find_first_of("([");
|
||||
if (pos != std::string::npos) { s.erase(pos); }
|
||||
const auto POS = s.find_first_of("([");
|
||||
if (POS != std::string::npos) { s.erase(POS); }
|
||||
while (!s.empty() && s.back() == ' ') { s.pop_back(); }
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// --- Enums ---
|
||||
enum class InputAction : int { // Acciones de entrada posibles en el juego
|
||||
enum class InputAction : std::uint8_t { // Acciones de entrada posibles en el juego
|
||||
// Inputs de movimiento
|
||||
UP,
|
||||
DOWN,
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@
|
||||
#include "game/gameplay/difficulty.hpp" // Para Difficulty
|
||||
#include "game/options.hpp" // Para SettingsOpt...
|
||||
|
||||
using json = nlohmann::json;
|
||||
using Json = nlohmann::json;
|
||||
|
||||
namespace Lang {
|
||||
std::unordered_map<std::string, std::string> texts;
|
||||
@@ -33,12 +33,12 @@ namespace Lang {
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
|
||||
try {
|
||||
json j;
|
||||
Json j;
|
||||
|
||||
if (!resource_data.empty()) {
|
||||
// Cargar desde datos del pack
|
||||
std::string content(resource_data.begin(), resource_data.end());
|
||||
j = json::parse(content);
|
||||
j = Json::parse(content);
|
||||
} else {
|
||||
// Fallback a filesystem directo
|
||||
std::ifstream rfile(file_path);
|
||||
@@ -81,23 +81,23 @@ namespace Lang {
|
||||
|
||||
// Obtiene un idioma del vector de idiomas a partir de un código
|
||||
auto getLanguage(Code code) -> Language {
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
const auto IT = std::ranges::find_if(languages,
|
||||
[code](const auto& lang) { return lang.code == code; });
|
||||
return it != languages.end() ? *it : languages[0];
|
||||
return IT != languages.end() ? *IT : languages[0];
|
||||
}
|
||||
|
||||
// Devuelve el código de un idioma a partir de un nombre
|
||||
auto getCodeFromName(const std::string& name) -> Code {
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
const auto IT = std::ranges::find_if(languages,
|
||||
[&name](const auto& lang) { return lang.name == name; });
|
||||
return it != languages.end() ? it->code : languages[0].code;
|
||||
return IT != languages.end() ? IT->code : languages[0].code;
|
||||
}
|
||||
|
||||
// Devuelve el nombre de un idioma a partir de un código
|
||||
auto getNameFromCode(Code code) -> std::string {
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
const auto IT = std::ranges::find_if(languages,
|
||||
[code](const auto& lang) { return lang.code == code; });
|
||||
return it != languages.end() ? it->name : languages[0].name;
|
||||
return IT != languages.end() ? IT->name : languages[0].name;
|
||||
}
|
||||
|
||||
// Actualiza los nombres de los idiomas
|
||||
@@ -144,9 +144,9 @@ namespace Lang {
|
||||
|
||||
// Obtiene una fichero a partir de un lang::Code
|
||||
auto getLanguageFileName(Lang::Code code) -> std::string {
|
||||
const auto it = std::ranges::find_if(languages,
|
||||
const auto IT = std::ranges::find_if(languages,
|
||||
[code](const auto& lang) { return lang.code == code; });
|
||||
const auto& file = (it != languages.end()) ? it->file_name : languages[0].file_name;
|
||||
const auto& file = (IT != languages.end()) ? IT->file_name : languages[0].file_name;
|
||||
return Asset::get()->getPath(file);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <string> // Para string, basic_string
|
||||
#include <utility> // Para move
|
||||
|
||||
// --- Namespace Lang: gestión de idiomas y textos ---
|
||||
namespace Lang {
|
||||
// --- Enums ---
|
||||
enum class Code : int {
|
||||
enum class Code : std::uint8_t {
|
||||
SPANISH = 0, // Español
|
||||
VALENCIAN = 1, // Valenciano
|
||||
ENGLISH = 2 // Inglés
|
||||
|
||||
@@ -29,10 +29,10 @@ Background::Background(float total_progress_to_complete)
|
||||
moon_texture_(Resource::get()->getTexture("game_moon.png")),
|
||||
grass_sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("game_grass.png"), Resource::get()->getAnimation("game_grass.ani"))),
|
||||
|
||||
total_progress_to_complete_(total_progress_to_complete),
|
||||
progress_per_stage_(total_progress_to_complete_ / STAGES),
|
||||
sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR),
|
||||
minimum_completed_progress_(total_progress_to_complete_ * MINIMUM_COMPLETED_PROGRESS_PERCENTAGE),
|
||||
TOTAL_PROGRESS_TO_COMPLETE(total_progress_to_complete),
|
||||
PROGRESS_PER_STAGE(TOTAL_PROGRESS_TO_COMPLETE / STAGES),
|
||||
SUM_COMPLETION_PROGRESS(TOTAL_PROGRESS_TO_COMPLETE * SUN_COMPLETION_FACTOR),
|
||||
MINIMUM_COMPLETED_PROGRESS(TOTAL_PROGRESS_TO_COMPLETE * MINIMUM_COMPLETED_PROGRESS_PERCENTAGE),
|
||||
|
||||
rect_(SDL_FRect{.x = 0, .y = 0, .w = static_cast<float>(gradients_texture_->getWidth() / 2), .h = static_cast<float>(gradients_texture_->getHeight() / 2)}),
|
||||
src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
|
||||
@@ -167,7 +167,7 @@ void Background::incrementProgress(float amount) {
|
||||
if (state_ == State::NORMAL) {
|
||||
float old_progress = progress_;
|
||||
progress_ += amount;
|
||||
progress_ = std::min(progress_, total_progress_to_complete_);
|
||||
progress_ = std::min(progress_, TOTAL_PROGRESS_TO_COMPLETE);
|
||||
|
||||
// Notifica el cambio si hay callback y el progreso cambió
|
||||
if (progress_callback_ && progress_ != old_progress) {
|
||||
@@ -179,7 +179,7 @@ void Background::incrementProgress(float amount) {
|
||||
// Establece la progresión absoluta
|
||||
void Background::setProgress(float absolute_progress) {
|
||||
float old_progress = progress_;
|
||||
progress_ = std::clamp(absolute_progress, 0.0F, total_progress_to_complete_);
|
||||
progress_ = std::clamp(absolute_progress, 0.0F, TOTAL_PROGRESS_TO_COMPLETE);
|
||||
|
||||
// Notifica el cambio si hay callback y el progreso cambió
|
||||
if (progress_callback_ && progress_ != old_progress) {
|
||||
@@ -282,27 +282,27 @@ void Background::updateProgression(float delta_time) {
|
||||
float eased_t = easeOutCubic(static_cast<double>(t));
|
||||
|
||||
// Interpolación desde progreso inicial hasta mínimo
|
||||
float progress_range = completion_initial_progress_ - minimum_completed_progress_;
|
||||
float progress_range = completion_initial_progress_ - MINIMUM_COMPLETED_PROGRESS;
|
||||
progress_ = completion_initial_progress_ - (progress_range * eased_t);
|
||||
} else {
|
||||
// Transición completada, fijar al valor mínimo
|
||||
progress_ = minimum_completed_progress_;
|
||||
progress_ = MINIMUM_COMPLETED_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
// Calcula la transición de los diferentes fondos
|
||||
const float GRADIENT_NUMBER_FLOAT = std::min(progress_ / progress_per_stage_, 3.0F);
|
||||
const float GRADIENT_NUMBER_FLOAT = std::min(progress_ / PROGRESS_PER_STAGE, 3.0F);
|
||||
const float PERCENT = GRADIENT_NUMBER_FLOAT - static_cast<int>(GRADIENT_NUMBER_FLOAT);
|
||||
|
||||
gradient_number_ = static_cast<size_t>(GRADIENT_NUMBER_FLOAT);
|
||||
transition_ = PERCENT;
|
||||
|
||||
// Calcula la posición del sol
|
||||
const float SUN_PROGRESSION = std::min(progress_ / sun_completion_progress_, 1.0F);
|
||||
const float SUN_PROGRESSION = std::min(progress_ / SUM_COMPLETION_PROGRESS, 1.0F);
|
||||
sun_index_ = static_cast<size_t>(SUN_PROGRESSION * (sun_path_.size() - 1));
|
||||
|
||||
// Calcula la posición de la luna
|
||||
const float MOON_PROGRESSION = std::min(progress_ / total_progress_to_complete_, 1.0F);
|
||||
const float MOON_PROGRESSION = std::min(progress_ / TOTAL_PROGRESS_TO_COMPLETE, 1.0F);
|
||||
moon_index_ = static_cast<size_t>(MOON_PROGRESSION * (moon_path_.size() - 1));
|
||||
|
||||
// Actualiza la velocidad de las nubes
|
||||
@@ -318,12 +318,12 @@ void Background::updateCloudsSpeed() {
|
||||
|
||||
// Velocidad base según progreso (de -3.0 a -120.0 píxeles/segundo, igual que la versión original)
|
||||
float base_clouds_speed = (-CLOUDS_INITIAL_SPEED_PX_PER_S) +
|
||||
(-CLOUDS_FINAL_SPEED_RANGE_PX_PER_S * (progress_ / total_progress_to_complete_));
|
||||
(-CLOUDS_FINAL_SPEED_RANGE_PX_PER_S * (progress_ / TOTAL_PROGRESS_TO_COMPLETE));
|
||||
|
||||
// En estado completado, las nubes se ralentizan gradualmente
|
||||
if (state_ == State::COMPLETED) {
|
||||
float completion_factor = (progress_ - minimum_completed_progress_) /
|
||||
(total_progress_to_complete_ - minimum_completed_progress_);
|
||||
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) /
|
||||
(TOTAL_PROGRESS_TO_COMPLETE - MINIMUM_COMPLETED_PROGRESS);
|
||||
completion_factor = std::max(0.1F, completion_factor);
|
||||
base_clouds_speed *= completion_factor;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <array> // Para array
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <functional> // Para function
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
#include <vector> // Para vector
|
||||
@@ -19,7 +20,7 @@ class AnimatedSprite;
|
||||
class Background {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class State {
|
||||
enum class State : std::uint8_t {
|
||||
NORMAL, // Progresión normal del día
|
||||
COMPLETED // Reducción gradual de la actividad
|
||||
};
|
||||
@@ -87,10 +88,10 @@ class Background {
|
||||
std::unique_ptr<AnimatedSprite> grass_sprite_; // Sprite con la hierba
|
||||
|
||||
// --- Variables de configuración ---
|
||||
const float total_progress_to_complete_; // Progreso total para completar
|
||||
const float progress_per_stage_; // Progreso por etapa
|
||||
const float sun_completion_progress_; // Progreso de completado del sol
|
||||
const float minimum_completed_progress_; // Progreso mínimo calculado dinámicamente
|
||||
const float TOTAL_PROGRESS_TO_COMPLETE; // Progreso total para completar
|
||||
const float PROGRESS_PER_STAGE; // Progreso por etapa
|
||||
const float SUM_COMPLETION_PROGRESS; // Progreso de completado del sol
|
||||
const float MINIMUM_COMPLETED_PROGRESS; // Progreso mínimo calculado dinámicamente
|
||||
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
|
||||
|
||||
// --- Variables de estado ---
|
||||
|
||||
@@ -481,7 +481,7 @@ void Fade::activate() {
|
||||
case Type::DIAGONAL: {
|
||||
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||
square_.clear();
|
||||
square_age_.assign(num_squares_width_ * num_squares_height_, -1);
|
||||
square_age_.assign(static_cast<size_t>(num_squares_width_) * num_squares_height_, -1);
|
||||
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) {
|
||||
rect1_.x = (i % num_squares_width_) * rect1_.w;
|
||||
rect1_.y = (i / num_squares_width_) * rect1_.h;
|
||||
|
||||
+197
-185
@@ -8,145 +8,233 @@
|
||||
#include <string> // Para char_traits, operator==, basic_string, string
|
||||
|
||||
namespace GIF {
|
||||
inline void readBytes(const uint8_t *&buffer, void *dst, size_t size) {
|
||||
std::memcpy(dst, buffer, size);
|
||||
buffer += size;
|
||||
}
|
||||
|
||||
void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) {
|
||||
if (code_length < 2 || code_length > 12) {
|
||||
std::cout << "Invalid LZW code length: " << code_length << '\n';
|
||||
throw std::runtime_error("Invalid LZW code length");
|
||||
namespace {
|
||||
inline void readBytes(const uint8_t *&buffer, void *dst, size_t size) {
|
||||
std::memcpy(dst, buffer, size);
|
||||
buffer += size;
|
||||
}
|
||||
|
||||
int i, bit;
|
||||
int prev = -1;
|
||||
std::vector<DictionaryEntry> dictionary;
|
||||
int dictionary_ind;
|
||||
unsigned int mask = 0x01;
|
||||
int reset_code_length = code_length;
|
||||
int clear_code = 1 << code_length;
|
||||
int stop_code = clear_code + 1;
|
||||
int match_len = 0;
|
||||
|
||||
dictionary.resize(1 << (code_length + 1));
|
||||
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
|
||||
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
||||
dictionary[dictionary_ind].prev = -1;
|
||||
dictionary[dictionary_ind].len = 1;
|
||||
// Llavor del diccionari LZW: 0..N-1 com a entrades base, i salta 2 (clear_code + stop_code).
|
||||
void resetDictionary(std::vector<DictionaryEntry> &dict, int code_length, int &dictionary_ind) {
|
||||
dict.resize(1 << (code_length + 1));
|
||||
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
|
||||
dict[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
||||
dict[dictionary_ind].prev = -1;
|
||||
dict[dictionary_ind].len = 1;
|
||||
}
|
||||
dictionary_ind += 2;
|
||||
}
|
||||
dictionary_ind += 2;
|
||||
|
||||
while (input_length > 0) {
|
||||
// Llig `code_length + 1` bits LSB-first del flux d'entrada. Llança si s'acaba el buffer.
|
||||
auto readNextCode(const uint8_t *&input, int &input_length, int code_length, unsigned int &mask) -> int {
|
||||
int code = 0;
|
||||
for (i = 0; i < (code_length + 1); i++) {
|
||||
for (int i = 0; i < code_length + 1; i++) {
|
||||
if (input_length <= 0) {
|
||||
std::cout << "Unexpected end of input in decompress" << '\n';
|
||||
throw std::runtime_error("Unexpected end of input in decompress");
|
||||
}
|
||||
bit = ((*input & mask) != 0) ? 1 : 0;
|
||||
const int BIT = ((*input & mask) != 0) ? 1 : 0;
|
||||
mask <<= 1;
|
||||
if (mask == 0x100) {
|
||||
mask = 0x01;
|
||||
input++;
|
||||
input_length--;
|
||||
}
|
||||
code |= (bit << i);
|
||||
code |= (BIT << i);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
if (code == clear_code) {
|
||||
code_length = reset_code_length;
|
||||
dictionary.resize(1 << (code_length + 1));
|
||||
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
|
||||
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
|
||||
dictionary[dictionary_ind].prev = -1;
|
||||
dictionary[dictionary_ind].len = 1;
|
||||
}
|
||||
dictionary_ind += 2;
|
||||
prev = -1;
|
||||
continue;
|
||||
} else if (code == stop_code) {
|
||||
break;
|
||||
// Afig una nova entrada al diccionari. Resol el cas especial KwKwK (code == dictionary_ind)
|
||||
// començant la cadena des de `prev` en lloc de des de `code`.
|
||||
void addDictionaryEntry(std::vector<DictionaryEntry> &dict, int dictionary_ind, int code, int prev) {
|
||||
int ptr = (code == dictionary_ind) ? prev : code;
|
||||
while (dict[ptr].prev != -1) {
|
||||
ptr = dict[ptr].prev;
|
||||
}
|
||||
dict[dictionary_ind].byte = dict[ptr].byte;
|
||||
dict[dictionary_ind].prev = prev;
|
||||
dict[dictionary_ind].len = dict[prev].len + 1;
|
||||
}
|
||||
|
||||
if (prev > -1 && code_length < 12) {
|
||||
if (code > dictionary_ind) {
|
||||
std::cout << "LZW error: code (" << code << ") exceeds dictionary_ind (" << dictionary_ind << ")" << '\n';
|
||||
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
||||
}
|
||||
|
||||
int ptr;
|
||||
if (code == dictionary_ind) {
|
||||
ptr = prev;
|
||||
while (dictionary[ptr].prev != -1)
|
||||
ptr = dictionary[ptr].prev;
|
||||
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
|
||||
} else {
|
||||
ptr = code;
|
||||
while (dictionary[ptr].prev != -1)
|
||||
ptr = dictionary[ptr].prev;
|
||||
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
|
||||
}
|
||||
dictionary[dictionary_ind].prev = prev;
|
||||
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
|
||||
dictionary_ind++;
|
||||
|
||||
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
|
||||
code_length++;
|
||||
dictionary.resize(1 << (code_length + 1));
|
||||
}
|
||||
}
|
||||
|
||||
prev = code;
|
||||
|
||||
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
|
||||
std::cout << "Invalid LZW code " << code << ", dictionary size " << static_cast<unsigned long>(dictionary.size()) << '\n';
|
||||
throw std::runtime_error("LZW error: invalid code encountered");
|
||||
}
|
||||
|
||||
int curCode = code;
|
||||
match_len = dictionary[curCode].len;
|
||||
while (curCode != -1) {
|
||||
out[dictionary[curCode].len - 1] = dictionary[curCode].byte;
|
||||
if (dictionary[curCode].prev == curCode) {
|
||||
// Escriu la cadena de bytes associada a `code` en `out` (en ordre invers seguint .prev).
|
||||
// Retorna la longitud del match per avançar el cursor de l'eixida.
|
||||
auto emitMatch(const std::vector<DictionaryEntry> &dict, int code, uint8_t *out) -> int {
|
||||
const int MATCH_LEN = dict[code].len;
|
||||
int cur_code = code;
|
||||
while (cur_code != -1) {
|
||||
out[dict[cur_code].len - 1] = dict[cur_code].byte;
|
||||
if (dict[cur_code].prev == cur_code) {
|
||||
std::cout << "Internal error; self-reference detected." << '\n';
|
||||
throw std::runtime_error("Internal error in decompress: self-reference");
|
||||
}
|
||||
curCode = dictionary[curCode].prev;
|
||||
cur_code = dict[cur_code].prev;
|
||||
}
|
||||
out += match_len;
|
||||
return MATCH_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Gif::readSubBlocks(const uint8_t *&buffer) {
|
||||
std::vector<uint8_t> data;
|
||||
uint8_t block_size = *buffer;
|
||||
buffer++;
|
||||
while (block_size != 0) {
|
||||
data.insert(data.end(), buffer, buffer + block_size);
|
||||
buffer += block_size;
|
||||
block_size = *buffer;
|
||||
// Descompone (uncompress) el bloque comprimido usando LZW.
|
||||
void decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) {
|
||||
if (code_length < 2 || code_length > 12) {
|
||||
std::cout << "Invalid LZW code length: " << code_length << '\n';
|
||||
throw std::runtime_error("Invalid LZW code length");
|
||||
}
|
||||
|
||||
int prev = -1;
|
||||
std::vector<DictionaryEntry> dictionary;
|
||||
int dictionary_ind = 0;
|
||||
unsigned int mask = 0x01;
|
||||
const int RESET_CODE_LENGTH = code_length;
|
||||
const int CLEAR_CODE = 1 << code_length;
|
||||
const int STOP_CODE = CLEAR_CODE + 1;
|
||||
|
||||
resetDictionary(dictionary, code_length, dictionary_ind);
|
||||
|
||||
while (input_length > 0) {
|
||||
const int CODE = readNextCode(input, input_length, code_length, mask);
|
||||
|
||||
if (CODE == CLEAR_CODE) {
|
||||
code_length = RESET_CODE_LENGTH;
|
||||
resetDictionary(dictionary, code_length, dictionary_ind);
|
||||
prev = -1;
|
||||
continue;
|
||||
}
|
||||
if (CODE == STOP_CODE) { break; }
|
||||
|
||||
if (prev > -1 && code_length < 12) {
|
||||
if (CODE > dictionary_ind) {
|
||||
std::cout << "LZW error: code (" << CODE << ") exceeds dictionary_ind (" << dictionary_ind << ")" << '\n';
|
||||
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
|
||||
}
|
||||
addDictionaryEntry(dictionary, dictionary_ind, CODE, prev);
|
||||
dictionary_ind++;
|
||||
|
||||
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
|
||||
code_length++;
|
||||
dictionary.resize(1 << (code_length + 1));
|
||||
}
|
||||
}
|
||||
|
||||
prev = CODE;
|
||||
|
||||
if (CODE < 0 || static_cast<size_t>(CODE) >= dictionary.size()) {
|
||||
std::cout << "Invalid LZW code " << CODE << ", dictionary size " << static_cast<unsigned long>(dictionary.size()) << '\n';
|
||||
throw std::runtime_error("LZW error: invalid code encountered");
|
||||
}
|
||||
|
||||
out += emitMatch(dictionary, CODE, out);
|
||||
}
|
||||
}
|
||||
|
||||
// Lee los sub-bloques de datos y los acumula en un std::vector<uint8_t>.
|
||||
auto readSubBlocks(const uint8_t *&buffer) -> std::vector<uint8_t> {
|
||||
std::vector<uint8_t> data;
|
||||
uint8_t block_size = *buffer;
|
||||
buffer++;
|
||||
while (block_size != 0) {
|
||||
data.insert(data.end(), buffer, buffer + block_size);
|
||||
buffer += block_size;
|
||||
block_size = *buffer;
|
||||
buffer++;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits) {
|
||||
ImageDescriptor image_descriptor;
|
||||
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
|
||||
// Procesa el Image Descriptor y retorna el vector de datos sin comprimir.
|
||||
auto processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits) -> std::vector<uint8_t> {
|
||||
ImageDescriptor image_descriptor;
|
||||
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
|
||||
|
||||
uint8_t lzw_code_size;
|
||||
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
|
||||
uint8_t lzw_code_size;
|
||||
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
|
||||
|
||||
std::vector<uint8_t> compressed_data = readSubBlocks(buffer);
|
||||
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
|
||||
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
|
||||
std::vector<uint8_t> compressed_data = readSubBlocks(buffer);
|
||||
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
|
||||
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
|
||||
|
||||
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
|
||||
return uncompressed_data;
|
||||
}
|
||||
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Gif::loadPalette(const uint8_t *buffer) {
|
||||
// Procesa el stream completo del GIF y devuelve los datos sin comprimir.
|
||||
auto processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h) -> std::vector<uint8_t> {
|
||||
uint8_t header[6];
|
||||
std::memcpy(header, buffer, 6);
|
||||
buffer += 6;
|
||||
|
||||
std::string header_str(reinterpret_cast<char *>(header), 6);
|
||||
if (header_str != "GIF87a" && header_str != "GIF89a") {
|
||||
std::cout << "Formato de archivo GIF inválido: " << header_str << '\n';
|
||||
throw std::runtime_error("Formato de archivo GIF inválido.");
|
||||
}
|
||||
|
||||
ScreenDescriptor screen_descriptor;
|
||||
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
|
||||
|
||||
w = screen_descriptor.width;
|
||||
h = screen_descriptor.height;
|
||||
|
||||
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
|
||||
std::vector<RGB> global_color_table;
|
||||
if ((screen_descriptor.fields & 0x80) != 0) {
|
||||
const size_t GLOBAL_COLOR_TABLE_SIZE = 1U << (((screen_descriptor.fields & 0x07) + 1));
|
||||
global_color_table.resize(GLOBAL_COLOR_TABLE_SIZE);
|
||||
std::memcpy(global_color_table.data(), buffer, 3 * GLOBAL_COLOR_TABLE_SIZE);
|
||||
buffer += 3 * GLOBAL_COLOR_TABLE_SIZE;
|
||||
}
|
||||
|
||||
uint8_t block_type = *buffer++;
|
||||
while (block_type != TRAILER) {
|
||||
if (block_type == EXTENSION_INTRODUCER) {
|
||||
uint8_t extension_label = *buffer++;
|
||||
switch (extension_label) {
|
||||
case GRAPHIC_CONTROL: {
|
||||
uint8_t block_size = *buffer++;
|
||||
buffer += block_size;
|
||||
uint8_t sub_block_size = *buffer++;
|
||||
while (sub_block_size != 0) {
|
||||
buffer += sub_block_size;
|
||||
sub_block_size = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APPLICATION_EXTENSION:
|
||||
case COMMENT_EXTENSION:
|
||||
case PLAINTEXT_EXTENSION: {
|
||||
uint8_t block_size = *buffer++;
|
||||
buffer += block_size;
|
||||
uint8_t sub_block_size = *buffer++;
|
||||
while (sub_block_size != 0) {
|
||||
buffer += sub_block_size;
|
||||
sub_block_size = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
uint8_t block_size = *buffer++;
|
||||
buffer += block_size;
|
||||
uint8_t sub_block_size = *buffer++;
|
||||
while (sub_block_size != 0) {
|
||||
buffer += sub_block_size;
|
||||
sub_block_size = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (block_type == IMAGE_DESCRIPTOR) {
|
||||
return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
|
||||
} else {
|
||||
std::cout << "Unrecognized block type: 0x" << std::hex << static_cast<int>(block_type) << std::dec << '\n';
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
block_type = *buffer++;
|
||||
}
|
||||
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
auto loadPalette(const uint8_t *buffer) -> std::vector<uint32_t> {
|
||||
uint8_t header[6];
|
||||
std::memcpy(header, buffer, 6);
|
||||
buffer += 6;
|
||||
@@ -156,7 +244,7 @@ namespace GIF {
|
||||
buffer += sizeof(ScreenDescriptor);
|
||||
|
||||
std::vector<uint32_t> global_color_table;
|
||||
if (screen_descriptor.fields & 0x80) {
|
||||
if ((screen_descriptor.fields & 0x80) != 0) {
|
||||
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
||||
global_color_table.resize(global_color_table_size);
|
||||
for (int i = 0; i < global_color_table_size; ++i) {
|
||||
@@ -170,83 +258,7 @@ namespace GIF {
|
||||
return global_color_table;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Gif::processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h) {
|
||||
uint8_t header[6];
|
||||
std::memcpy(header, buffer, 6);
|
||||
buffer += 6;
|
||||
|
||||
std::string headerStr(reinterpret_cast<char *>(header), 6);
|
||||
if (headerStr != "GIF87a" && headerStr != "GIF89a") {
|
||||
std::cout << "Formato de archivo GIF inválido: " << headerStr << '\n';
|
||||
throw std::runtime_error("Formato de archivo GIF inválido.");
|
||||
}
|
||||
|
||||
ScreenDescriptor screen_descriptor;
|
||||
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
|
||||
|
||||
w = screen_descriptor.width;
|
||||
h = screen_descriptor.height;
|
||||
|
||||
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
|
||||
std::vector<RGB> global_color_table;
|
||||
if (screen_descriptor.fields & 0x80) {
|
||||
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
|
||||
global_color_table.resize(global_color_table_size);
|
||||
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
|
||||
buffer += 3 * global_color_table_size;
|
||||
}
|
||||
|
||||
uint8_t block_type = *buffer++;
|
||||
while (block_type != TRAILER) {
|
||||
if (block_type == EXTENSION_INTRODUCER) {
|
||||
uint8_t extension_label = *buffer++;
|
||||
switch (extension_label) {
|
||||
case GRAPHIC_CONTROL: {
|
||||
uint8_t blockSize = *buffer++;
|
||||
buffer += blockSize;
|
||||
uint8_t subBlockSize = *buffer++;
|
||||
while (subBlockSize != 0) {
|
||||
buffer += subBlockSize;
|
||||
subBlockSize = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APPLICATION_EXTENSION:
|
||||
case COMMENT_EXTENSION:
|
||||
case PLAINTEXT_EXTENSION: {
|
||||
uint8_t blockSize = *buffer++;
|
||||
buffer += blockSize;
|
||||
uint8_t subBlockSize = *buffer++;
|
||||
while (subBlockSize != 0) {
|
||||
buffer += subBlockSize;
|
||||
subBlockSize = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
uint8_t blockSize = *buffer++;
|
||||
buffer += blockSize;
|
||||
uint8_t subBlockSize = *buffer++;
|
||||
while (subBlockSize != 0) {
|
||||
buffer += subBlockSize;
|
||||
subBlockSize = *buffer++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (block_type == IMAGE_DESCRIPTOR) {
|
||||
return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
|
||||
} else {
|
||||
std::cout << "Unrecognized block type: 0x" << std::hex << static_cast<int>(block_type) << std::dec << '\n';
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
block_type = *buffer++;
|
||||
}
|
||||
|
||||
return std::vector<uint8_t>{};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) {
|
||||
auto loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) -> std::vector<uint8_t> {
|
||||
return processGifStream(buffer, w, h);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,29 +64,12 @@ namespace GIF {
|
||||
uint8_t foreground_color, background_color;
|
||||
};
|
||||
|
||||
class Gif {
|
||||
public:
|
||||
// Descompone (uncompress) el bloque comprimido usando LZW.
|
||||
// Este método puede lanzar std::runtime_error en caso de error.
|
||||
void decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out);
|
||||
// Carga la paleta (global color table) a partir de un buffer,
|
||||
// retornándola en un vector de uint32_t (cada color se compone de R, G, B).
|
||||
auto loadPalette(const uint8_t *buffer) -> std::vector<uint32_t>;
|
||||
|
||||
// Carga la paleta (global color table) a partir de un buffer,
|
||||
// retornándola en un vector de uint32_t (cada color se compone de R, G, B).
|
||||
std::vector<uint32_t> loadPalette(const uint8_t *buffer);
|
||||
|
||||
// Carga el stream GIF; devuelve un vector con los datos de imagen sin comprimir y
|
||||
// asigna el ancho y alto mediante referencias.
|
||||
std::vector<uint8_t> loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h);
|
||||
|
||||
private:
|
||||
// Lee los sub-bloques de datos y los acumula en un std::vector<uint8_t>.
|
||||
std::vector<uint8_t> readSubBlocks(const uint8_t *&buffer);
|
||||
|
||||
// Procesa el Image Descriptor y retorna el vector de datos sin comprimir.
|
||||
std::vector<uint8_t> processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits);
|
||||
|
||||
// Procesa el stream completo del GIF y devuelve los datos sin comprimir.
|
||||
std::vector<uint8_t> processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h);
|
||||
};
|
||||
// Carga el stream GIF; devuelve un vector con los datos de imagen sin comprimir y
|
||||
// asigna el ancho y alto mediante referencias.
|
||||
auto loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) -> std::vector<uint8_t>;
|
||||
|
||||
} // namespace GIF
|
||||
|
||||
@@ -320,49 +320,50 @@ void Screen::renderShake() {
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
// Compone la línia d'informació de debug: "fps - driver - shader preset"
|
||||
auto Screen::buildDebugInfoText() const -> std::string {
|
||||
std::string info_text = std::to_string(fps_.last_value) + " fps";
|
||||
|
||||
// Driver GPU
|
||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||
const std::string DRIVER = shader_backend_->getDriverName();
|
||||
info_text += DRIVER.empty() ? "" : " - " + toLower(DRIVER);
|
||||
} else {
|
||||
info_text += " - sdl";
|
||||
}
|
||||
|
||||
// Shader + preset (només si està activat)
|
||||
if (!Options::video.shader.enabled) { return info_text; }
|
||||
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
const std::string PRESET_NAME = Options::crtpi_presets.empty() ? "" : Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset)).name;
|
||||
info_text += " - crtpi " + toLower(PRESET_NAME);
|
||||
} else {
|
||||
const std::string PRESET_NAME = Options::postfx_presets.empty() ? "" : Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset)).name;
|
||||
info_text += " - postfx " + toLower(PRESET_NAME);
|
||||
if (Options::video.supersampling.enabled) { info_text += " (ss)"; }
|
||||
}
|
||||
return info_text;
|
||||
}
|
||||
|
||||
// Muestra información por pantalla
|
||||
void Screen::renderInfo() const {
|
||||
if (debug_info_.show) {
|
||||
const Color GOLD(0xFF, 0xD7, 0x00);
|
||||
const Color GOLD_SHADOW = GOLD.DARKEN(150);
|
||||
if (!debug_info_.show) { return; }
|
||||
|
||||
// Construir texto: fps - driver - preset
|
||||
std::string info_text = std::to_string(fps_.last_value) + " fps";
|
||||
const Color GOLD(0xFF, 0xD7, 0x00);
|
||||
const Color GOLD_SHADOW = GOLD.darken(150);
|
||||
|
||||
// Driver GPU
|
||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||
const std::string DRIVER = shader_backend_->getDriverName();
|
||||
if (!DRIVER.empty()) {
|
||||
info_text += " - " + toLower(DRIVER);
|
||||
}
|
||||
} else {
|
||||
info_text += " - sdl";
|
||||
}
|
||||
|
||||
// Shader + preset
|
||||
if (Options::video.shader.enabled) {
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
const std::string PRESET_NAME = Options::crtpi_presets.empty() ? "" : Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset)).name;
|
||||
info_text += " - crtpi " + toLower(PRESET_NAME);
|
||||
} else {
|
||||
const std::string PRESET_NAME = Options::postfx_presets.empty() ? "" : Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset)).name;
|
||||
info_text += " - postfx " + toLower(PRESET_NAME);
|
||||
if (Options::video.supersampling.enabled) { info_text += " (ss)"; }
|
||||
}
|
||||
}
|
||||
|
||||
// Centrado arriba
|
||||
const int TEXT_WIDTH = debug_info_.text->length(info_text);
|
||||
const int X_POS = (static_cast<int>(param.game.width) - TEXT_WIDTH) / 2;
|
||||
debug_info_.text->writeDX(Text::COLOR | Text::STROKE, X_POS, 1, info_text, 1, GOLD, 1, GOLD_SHADOW);
|
||||
const std::string INFO_TEXT = buildDebugInfoText();
|
||||
const int TEXT_WIDTH = debug_info_.text->length(INFO_TEXT);
|
||||
const int X_POS = (static_cast<int>(param.game.width) - TEXT_WIDTH) / 2;
|
||||
debug_info_.text->writeDX(Text::COLOR | Text::STROKE, X_POS, 1, INFO_TEXT, 1, GOLD, 1, GOLD_SHADOW);
|
||||
|
||||
#ifdef RECORDING
|
||||
const std::string REC_TEXT = "recording";
|
||||
const int REC_WIDTH = debug_info_.text->length(REC_TEXT);
|
||||
const int REC_X = (static_cast<int>(param.game.width) - REC_WIDTH) / 2;
|
||||
debug_info_.text->writeDX(Text::COLOR | Text::STROKE, REC_X, 1 + debug_info_.text->getCharacterSize(), REC_TEXT, 1, GOLD, 1, GOLD_SHADOW);
|
||||
const std::string REC_TEXT = "recording";
|
||||
const int REC_WIDTH = debug_info_.text->length(REC_TEXT);
|
||||
const int REC_X = (static_cast<int>(param.game.width) - REC_WIDTH) / 2;
|
||||
debug_info_.text->writeDX(Text::COLOR | Text::STROKE, REC_X, 1 + debug_info_.text->getCharacterSize(), REC_TEXT, 1, GOLD, 1, GOLD_SHADOW);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Inicializa shaders (SDL3GPU)
|
||||
@@ -380,8 +381,8 @@ void Screen::initShaders() {
|
||||
Options::video.gpu.acceleration ? Options::video.gpu.preferred_driver : FALLBACK_DRIVER);
|
||||
}
|
||||
if (!self->shader_backend_->isHardwareAccelerated()) {
|
||||
const bool ok = self->shader_backend_->init(self->window_, self->game_canvas_, "", "");
|
||||
std::cout << "Screen::initShaders: SDL3GPUShader::init() = " << (ok ? "OK" : "FAILED") << '\n';
|
||||
const bool OK = self->shader_backend_->init(self->window_, self->game_canvas_, "", "");
|
||||
std::cout << "Screen::initShaders: SDL3GPUShader::init() = " << (OK ? "OK" : "FAILED") << '\n';
|
||||
}
|
||||
if (self->shader_backend_ && self->shader_backend_->isHardwareAccelerated()) {
|
||||
self->shader_backend_->setLinearUpscale(Options::video.supersampling.linear_upscale);
|
||||
|
||||
@@ -241,6 +241,7 @@ class Screen {
|
||||
void renderFlash(); // Dibuja el efecto de flash en la pantalla
|
||||
void renderShake(); // Aplica el efecto de agitar la pantalla
|
||||
void renderInfo() const; // Muestra información por pantalla
|
||||
[[nodiscard]] auto buildDebugInfoText() const -> std::string; // Compone fps + driver + shader/preset para renderInfo
|
||||
void renderPresent(); // Selecciona y ejecuta el método de renderizado adecuado
|
||||
void applyCurrentPostFXPreset(); // Aplica el preset PostFX activo al backend
|
||||
void applyCurrentCrtPiPreset(); // Aplica el preset CrtPi activo al backend
|
||||
|
||||
@@ -702,7 +702,7 @@ namespace Rendering {
|
||||
return;
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
/** @brief Identificador del shader de post-procesado activo */
|
||||
enum class ShaderType { POSTFX,
|
||||
enum class ShaderType : std::uint8_t { POSTFX,
|
||||
CRTPI };
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ auto CardSprite::enable() -> bool {
|
||||
|
||||
// Ángulo inicial
|
||||
rotate_.angle = start_angle_;
|
||||
rotate_.center = {pos_.w / 2.0F, pos_.h / 2.0F};
|
||||
rotate_.center = {.x = pos_.w / 2.0F, .y = pos_.h / 2.0F};
|
||||
|
||||
shadow_visible_ = true;
|
||||
return true;
|
||||
@@ -55,7 +55,7 @@ void CardSprite::startExit() {
|
||||
// Rotación continua
|
||||
rotate_.enabled = true;
|
||||
rotate_.amount = exit_rotate_amount_;
|
||||
rotate_.center = {pos_.w / 2.0F, pos_.h / 2.0F};
|
||||
rotate_.center = {.x = pos_.w / 2.0F, .y = pos_.h / 2.0F};
|
||||
}
|
||||
|
||||
// Actualiza según el estado
|
||||
@@ -80,7 +80,7 @@ void CardSprite::updateEntering(float delta_time) {
|
||||
double eased = entry_easing_(static_cast<double>(progress));
|
||||
|
||||
// Zoom: de start_zoom_ a 1.0 con rebote
|
||||
auto current_zoom = static_cast<float>(start_zoom_ + (1.0 - start_zoom_) * eased);
|
||||
auto current_zoom = static_cast<float>(start_zoom_ + ((1.0 - start_zoom_) * eased));
|
||||
horizontal_zoom_ = current_zoom;
|
||||
vertical_zoom_ = current_zoom;
|
||||
|
||||
@@ -90,8 +90,8 @@ void CardSprite::updateEntering(float delta_time) {
|
||||
// Posición: de entry_start a landing con easing suave (sin rebote)
|
||||
// Usamos easeOutCubic para que el desplazamiento sea fluido
|
||||
double pos_eased = easeOutCubic(static_cast<double>(progress));
|
||||
auto current_x = static_cast<float>(entry_start_x_ + (landing_x_ - entry_start_x_) * pos_eased);
|
||||
auto current_y = static_cast<float>(entry_start_y_ + (landing_y_ - entry_start_y_) * pos_eased);
|
||||
auto current_x = static_cast<float>(entry_start_x_ + ((landing_x_ - entry_start_x_) * pos_eased));
|
||||
auto current_y = static_cast<float>(entry_start_y_ + ((landing_y_ - entry_start_y_) * pos_eased));
|
||||
setPos(current_x, current_y);
|
||||
|
||||
// Detecta el primer toque (cuando el easing alcanza ~1.0 por primera vez)
|
||||
@@ -117,12 +117,9 @@ void CardSprite::updateExiting(float delta_time) {
|
||||
|
||||
// Ganar altura gradualmente (zoom hacia el objetivo)
|
||||
if (exit_zoom_speed_ > 0.0F && horizontal_zoom_ < exit_target_zoom_) {
|
||||
float new_zoom = horizontal_zoom_ + exit_zoom_speed_ * delta_time;
|
||||
if (new_zoom > exit_target_zoom_) {
|
||||
new_zoom = exit_target_zoom_;
|
||||
}
|
||||
horizontal_zoom_ = new_zoom;
|
||||
vertical_zoom_ = new_zoom;
|
||||
const float NEW_ZOOM = std::min(horizontal_zoom_ + (exit_zoom_speed_ * delta_time), exit_target_zoom_);
|
||||
horizontal_zoom_ = NEW_ZOOM;
|
||||
vertical_zoom_ = NEW_ZOOM;
|
||||
}
|
||||
|
||||
if (isOffScreen()) {
|
||||
@@ -164,8 +161,8 @@ void CardSprite::renderShadow() {
|
||||
|
||||
// Offset respecto a la tarjeta: base + extra proporcional a la altura
|
||||
// La sombra se aleja en diagonal abajo-derecha (opuesta a la luz en 0,0)
|
||||
float offset_x = shadow_offset_x_ + height * SHADOW_HEIGHT_MULTIPLIER;
|
||||
float offset_y = shadow_offset_y_ + height * SHADOW_HEIGHT_MULTIPLIER;
|
||||
float offset_x = shadow_offset_x_ + (height * SHADOW_HEIGHT_MULTIPLIER);
|
||||
float offset_y = shadow_offset_y_ + (height * SHADOW_HEIGHT_MULTIPLIER);
|
||||
|
||||
shadow_texture_->render(
|
||||
pos_.x + offset_x,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FPoint
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <functional> // Para function
|
||||
#include <memory> // Para shared_ptr
|
||||
|
||||
@@ -10,7 +11,7 @@
|
||||
class Texture;
|
||||
|
||||
// --- Estados de la tarjeta ---
|
||||
enum class CardState {
|
||||
enum class CardState : std::uint8_t {
|
||||
IDLE, // No activada todavía
|
||||
ENTERING, // Animación de entrada (zoom + rotación + desplazamiento con rebote)
|
||||
LANDED, // En reposo sobre la mesa
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FPoint
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <functional> // Para std::function
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <utility>
|
||||
@@ -12,12 +13,12 @@
|
||||
class Texture;
|
||||
|
||||
// --- Enums ---
|
||||
enum class PathType { // Tipos de recorrido
|
||||
enum class PathType : std::uint8_t { // Tipos de recorrido
|
||||
VERTICAL,
|
||||
HORIZONTAL,
|
||||
};
|
||||
|
||||
enum class PathCentered { // Centrado del recorrido
|
||||
enum class PathCentered : std::uint8_t { // Centrado del recorrido
|
||||
ON_X,
|
||||
ON_Y,
|
||||
NONE,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "core/rendering/sprite/smart_sprite.hpp"
|
||||
|
||||
#include "core/rendering/sprite/moving_sprite.hpp" // Para MovingSprite
|
||||
|
||||
// Actualiza la posición y comprueba si ha llegado a su destino (time-based)
|
||||
void SmartSprite::update(float delta_time) {
|
||||
if (enabled_) {
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <utility>
|
||||
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||
#include "core/rendering/sprite/moving_sprite.hpp" // Para MovingSprite
|
||||
|
||||
class Texture;
|
||||
|
||||
// --- Clase SmartSprite: sprite animado que se mueve hacia un destino y puede deshabilitarse automáticamente ---
|
||||
class SmartSprite : public AnimatedSprite {
|
||||
// --- Clase SmartSprite: sprite que se mueve hacia un destino y puede deshabilitarse automáticamente ---
|
||||
class SmartSprite : public MovingSprite {
|
||||
public:
|
||||
// --- Constructor y destructor ---
|
||||
explicit SmartSprite(std::shared_ptr<Texture> texture)
|
||||
: AnimatedSprite(std::move(texture)) {}
|
||||
: MovingSprite(std::move(texture)) {}
|
||||
~SmartSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
|
||||
@@ -251,11 +251,9 @@ auto Texture::loadSurface(const std::string& file_path) -> std::shared_ptr<Surfa
|
||||
}
|
||||
}
|
||||
|
||||
// Crear un objeto Gif y llamar a la función loadGif
|
||||
GIF::Gif gif;
|
||||
Uint16 w = 0;
|
||||
Uint16 h = 0;
|
||||
std::vector<Uint8> raw_pixels = gif.loadGif(buffer.data(), w, h);
|
||||
std::vector<Uint8> raw_pixels = GIF::loadGif(buffer.data(), w, h);
|
||||
if (raw_pixels.empty()) {
|
||||
std::cout << "Error: No se pudo cargar el GIF " << file_path << '\n';
|
||||
return nullptr;
|
||||
@@ -329,8 +327,7 @@ auto Texture::loadPaletteFromFile(const std::string& file_path) -> Palette {
|
||||
}
|
||||
|
||||
// Usar la nueva función loadPalette, que devuelve un vector<uint32_t>
|
||||
GIF::Gif gif;
|
||||
std::vector<uint32_t> pal = gif.loadPalette(buffer.data());
|
||||
std::vector<uint32_t> pal = GIF::loadPalette(buffer.data());
|
||||
if (pal.empty()) {
|
||||
std::cout << "Advertencia: No se encontró paleta en el archivo " << file_path << '\n';
|
||||
return palette; // Devuelve un vector vacío si no hay paleta
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_SetTextureColorMod, SDL_Renderer, SDL_Texture
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
|
||||
#include "utils/color.hpp" // Para Color
|
||||
|
||||
// --- Enums ---
|
||||
enum class TiledBGMode : int { // Modos de funcionamiento para el tileado de fondo
|
||||
enum class TiledBGMode : std::uint8_t { // Modos de funcionamiento para el tileado de fondo
|
||||
CIRCLE = 0,
|
||||
DIAGONAL = 1,
|
||||
RANDOM = 2,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "core/rendering/writer.hpp"
|
||||
|
||||
#include "core/rendering/text.hpp" // Para Text
|
||||
// Text es completat ací per `text_->write/length` via shared_ptr; include-cleaner no detecta l'ús indirecte.
|
||||
#include "core/rendering/text.hpp" // IWYU pragma: keep
|
||||
|
||||
// Actualiza el objeto (delta_time en ms)
|
||||
void Writer::update(float delta_time) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
class Asset {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Type : int {
|
||||
enum class Type : std::uint8_t {
|
||||
BITMAP, // Imágenes
|
||||
MUSIC, // Música
|
||||
SOUND, // Sonidos
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "core/resources/resource_loader.hpp"
|
||||
|
||||
bool AssetIntegrated::resource_pack_enabled = false;
|
||||
|
||||
void AssetIntegrated::initWithResourcePack(const std::string& executable_path,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "core/resources/asset.hpp"
|
||||
#include "core/resources/resource_loader.hpp"
|
||||
|
||||
// Extensión de Asset que integra ResourceLoader
|
||||
class AssetIntegrated : public Asset {
|
||||
|
||||
@@ -5,16 +5,12 @@
|
||||
#include <algorithm> // Para ranges::transform, ranges::find_if
|
||||
#include <array> // Para array
|
||||
#include <cstdlib> // Para exit
|
||||
#include <exception> // Para exception
|
||||
#include <filesystem> // Para exists, path, remove
|
||||
#include <fstream> // Para basic_ofstream, basic_ios, basic_ostream::write, ios, ofstream
|
||||
#include <iostream> // Para std::cout
|
||||
#include <iterator> // Para back_inserter
|
||||
#include <ranges> // Para __find_if_fn, find_if, __find_fn, find
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility> // Para move
|
||||
|
||||
#include "core/audio/jail_audio.hpp" // Para JA_LoadMusic, JA_LoadSound, JA_DeleteMusic, JA_DeleteSound
|
||||
#include "core/audio/jail_audio.hpp" // Para Ja::loadMusic, Ja::loadSound, Ja::deleteMusic, Ja::deleteSound
|
||||
#include "core/locale/lang.hpp" // Para getText
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/rendering/text.hpp" // Para Text
|
||||
@@ -27,9 +23,6 @@
|
||||
#include "utils/utils.hpp" // Para getFileName
|
||||
#include "version.h" // Para APP_NAME, GIT_HASH
|
||||
|
||||
struct JA_Music_t; // lines 11-11
|
||||
struct JA_Sound_t; // lines 12-12
|
||||
|
||||
// Helper para cargar archivos de audio desde pack o filesystem en memoria
|
||||
namespace {
|
||||
struct AudioData {
|
||||
@@ -140,37 +133,37 @@ void Resource::loadEssentialTextures() {
|
||||
|
||||
// Inicializa las listas de recursos sin cargar el contenido (modo lazy)
|
||||
void Resource::initResourceLists() {
|
||||
const auto file_to_name = [](const auto& file) { return getFileName(file); };
|
||||
const auto FILE_TO_NAME = [](const auto& file) { return getFileName(file); };
|
||||
|
||||
// Inicializa lista de sonidos
|
||||
const auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
const auto SOUND_LIST = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
sounds_.clear();
|
||||
sounds_.reserve(sound_list.size());
|
||||
std::ranges::transform(sound_list, std::back_inserter(sounds_), [&](const auto& file) { return ResourceSound(file_to_name(file)); });
|
||||
sounds_.reserve(SOUND_LIST.size());
|
||||
std::ranges::transform(SOUND_LIST, std::back_inserter(sounds_), [&](const auto& file) { return ResourceSound(FILE_TO_NAME(file)); });
|
||||
|
||||
// Inicializa lista de músicas
|
||||
const auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
const auto MUSIC_LIST = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
musics_.clear();
|
||||
musics_.reserve(music_list.size());
|
||||
std::ranges::transform(music_list, std::back_inserter(musics_), [&](const auto& file) { return ResourceMusic(file_to_name(file)); });
|
||||
musics_.reserve(MUSIC_LIST.size());
|
||||
std::ranges::transform(MUSIC_LIST, std::back_inserter(musics_), [&](const auto& file) { return ResourceMusic(FILE_TO_NAME(file)); });
|
||||
|
||||
// Inicializa lista de texturas
|
||||
const auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto TEXTURE_LIST = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
textures_.clear();
|
||||
textures_.reserve(texture_list.size());
|
||||
std::ranges::transform(texture_list, std::back_inserter(textures_), [&](const auto& file) { return ResourceTexture(file_to_name(file)); });
|
||||
textures_.reserve(TEXTURE_LIST.size());
|
||||
std::ranges::transform(TEXTURE_LIST, std::back_inserter(textures_), [&](const auto& file) { return ResourceTexture(FILE_TO_NAME(file)); });
|
||||
|
||||
// Inicializa lista de ficheros de texto
|
||||
const auto text_file_list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
const auto TEXT_FILE_LIST = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
text_files_.clear();
|
||||
text_files_.reserve(text_file_list.size());
|
||||
std::ranges::transform(text_file_list, std::back_inserter(text_files_), [&](const auto& file) { return ResourceTextFile(file_to_name(file)); });
|
||||
text_files_.reserve(TEXT_FILE_LIST.size());
|
||||
std::ranges::transform(TEXT_FILE_LIST, std::back_inserter(text_files_), [&](const auto& file) { return ResourceTextFile(FILE_TO_NAME(file)); });
|
||||
|
||||
// Inicializa lista de animaciones
|
||||
const auto animation_list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
const auto ANIMATION_LIST = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
animations_.clear();
|
||||
animations_.reserve(animation_list.size());
|
||||
std::ranges::transform(animation_list, std::back_inserter(animations_), [&](const auto& file) { return ResourceAnimation(file_to_name(file)); });
|
||||
animations_.reserve(ANIMATION_LIST.size());
|
||||
std::ranges::transform(ANIMATION_LIST, std::back_inserter(animations_), [&](const auto& file) { return ResourceAnimation(FILE_TO_NAME(file)); });
|
||||
|
||||
// Los demos se cargan directamente sin mostrar progreso (son pocos y pequeños)
|
||||
loadDemoDataQuiet();
|
||||
@@ -196,7 +189,7 @@ void Resource::initResourceLists() {
|
||||
}
|
||||
|
||||
// Obtiene el sonido a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getSound(const std::string& name) -> JA_Sound_t* {
|
||||
auto Resource::getSound(const std::string& name) -> Ja::Sound* {
|
||||
auto it = std::ranges::find_if(sounds_, [&name](const auto& s) -> auto { return s.name == name; });
|
||||
|
||||
if (it != sounds_.end()) {
|
||||
@@ -212,7 +205,7 @@ auto Resource::getSound(const std::string& name) -> JA_Sound_t* {
|
||||
}
|
||||
|
||||
// Obtiene la música a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getMusic(const std::string& name) -> JA_Music_t* {
|
||||
auto Resource::getMusic(const std::string& name) -> Ja::Music* {
|
||||
auto it = std::ranges::find_if(musics_, [&name](const auto& m) -> auto { return m.name == name; });
|
||||
|
||||
if (it != musics_.end()) {
|
||||
@@ -303,48 +296,48 @@ auto Resource::getDemoData(int index) -> DemoData& {
|
||||
|
||||
// --- Métodos de carga perezosa ---
|
||||
|
||||
auto Resource::loadSoundLazy(const std::string& name) -> JA_Sound_t* {
|
||||
auto Resource::loadSoundLazy(const std::string& name) -> Ja::Sound* {
|
||||
auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
for (const auto& file : sound_list) {
|
||||
if (getFileName(file) == name) {
|
||||
auto audio_data = loadAudioData(file);
|
||||
if (!audio_data.data.empty()) {
|
||||
return JA_LoadSound(audio_data.data.data(), audio_data.data.size());
|
||||
return Ja::loadSound(audio_data.data.data(), audio_data.data.size());
|
||||
}
|
||||
// Fallback a cargar desde disco si no está en pack
|
||||
return JA_LoadSound(file.c_str());
|
||||
return Ja::loadSound(file.c_str());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadMusicLazy(const std::string& name) -> JA_Music_t* {
|
||||
auto Resource::loadMusicLazy(const std::string& name) -> Ja::Music* {
|
||||
auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
for (const auto& file : music_list) {
|
||||
if (getFileName(file) == name) {
|
||||
auto audio_data = loadAudioData(file);
|
||||
if (!audio_data.data.empty()) {
|
||||
return JA_LoadMusic(audio_data.data.data(), audio_data.data.size());
|
||||
return Ja::loadMusic(audio_data.data.data(), audio_data.data.size());
|
||||
}
|
||||
// Fallback a cargar desde disco si no está en pack
|
||||
return JA_LoadMusic(file.c_str());
|
||||
return Ja::loadMusic(file.c_str());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadTextureLazy(const std::string& name) -> std::shared_ptr<Texture> {
|
||||
const auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto it = std::ranges::find_if(texture_list,
|
||||
const auto TEXTURE_LIST = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto IT = std::ranges::find_if(TEXTURE_LIST,
|
||||
[&name](const auto& file) { return getFileName(file) == name; });
|
||||
return it != texture_list.end() ? std::make_shared<Texture>(Screen::get()->getRenderer(), *it) : nullptr;
|
||||
return IT != TEXTURE_LIST.end() ? std::make_shared<Texture>(Screen::get()->getRenderer(), *IT) : nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadTextFileLazy(const std::string& name) -> std::shared_ptr<Text::File> {
|
||||
const auto text_file_list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
const auto it = std::ranges::find_if(text_file_list,
|
||||
const auto TEXT_FILE_LIST = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
const auto IT = std::ranges::find_if(TEXT_FILE_LIST,
|
||||
[&name](const auto& file) { return getFileName(file) == name; });
|
||||
return it != text_file_list.end() ? Text::loadFile(*it) : nullptr;
|
||||
return IT != TEXT_FILE_LIST.end() ? Text::loadFile(*IT) : nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadTextLazy(const std::string& name) -> std::shared_ptr<Text> {
|
||||
@@ -369,22 +362,22 @@ auto Resource::loadTextLazy(const std::string& name) -> std::shared_ptr<Text> {
|
||||
{.key = "smb2", .texture_file = "smb2.png", .text_file = "smb2.txt"},
|
||||
{.key = "smb2_grad", .texture_file = "smb2_grad.png", .text_file = "smb2.txt"}};
|
||||
|
||||
const auto it = std::ranges::find_if(TEXT_MAPPINGS,
|
||||
const auto IT = std::ranges::find_if(TEXT_MAPPINGS,
|
||||
[&name](const auto& mapping) { return mapping.key == name; });
|
||||
if (it == TEXT_MAPPINGS.end()) {
|
||||
if (IT == TEXT_MAPPINGS.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto texture = getTexture(it->texture_file); // Esto cargará la textura si no está cargada
|
||||
auto text_file = getTextFile(it->text_file); // Esto cargará el archivo de texto si no está cargado
|
||||
auto texture = getTexture(IT->texture_file); // Esto cargará la textura si no está cargada
|
||||
auto text_file = getTextFile(IT->text_file); // Esto cargará el archivo de texto si no está cargado
|
||||
return (texture && text_file) ? std::make_shared<Text>(texture, text_file) : nullptr;
|
||||
}
|
||||
|
||||
auto Resource::loadAnimationLazy(const std::string& name) -> AnimationsFileBuffer {
|
||||
const auto animation_list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
const auto it = std::ranges::find_if(animation_list,
|
||||
const auto ANIMATION_LIST = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
const auto IT = std::ranges::find_if(ANIMATION_LIST,
|
||||
[&name](const auto& file) { return getFileName(file) == name; });
|
||||
if (it != animation_list.end()) {
|
||||
return loadAnimationsFromFile(*it);
|
||||
if (IT != ANIMATION_LIST.end()) {
|
||||
return loadAnimationsFromFile(*IT);
|
||||
}
|
||||
// Si no se encuentra, retorna vector vacío
|
||||
return AnimationsFileBuffer{};
|
||||
@@ -427,80 +420,54 @@ auto Resource::isLoadDone() const -> bool {
|
||||
return stage_ == LoadStage::DONE;
|
||||
}
|
||||
|
||||
// Avança una etapa que descarrega una llista d'assets.
|
||||
void Resource::advanceListLoadStage(const std::vector<std::string>& list, void (Resource::*load_one)(size_t), LoadStage next_stage) {
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = next_stage;
|
||||
stage_index_ = 0;
|
||||
return;
|
||||
}
|
||||
(this->*load_one)(stage_index_++);
|
||||
}
|
||||
|
||||
// Bombea la máquina de etapas hasta agotar el presupuesto de tiempo o completar la carga.
|
||||
// Devuelve true cuando ya no queda nada por cargar.
|
||||
auto Resource::loadStep(int budget_ms) -> bool {
|
||||
if (stage_ == LoadStage::DONE) { return true; }
|
||||
|
||||
const Uint64 start_ns = SDL_GetTicksNS();
|
||||
const Uint64 budget_ns = static_cast<Uint64>(budget_ms) * 1'000'000ULL;
|
||||
const Uint64 START_NS = SDL_GetTicksNS();
|
||||
const Uint64 BUDGET_NS = static_cast<Uint64>(budget_ms) * 1'000'000ULL;
|
||||
|
||||
while (stage_ != LoadStage::DONE) {
|
||||
switch (stage_) {
|
||||
case LoadStage::SOUNDS: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
if (stage_index_ == 0) { sounds_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::MUSICS;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneSound(stage_index_++);
|
||||
advanceListLoadStage(Asset::get()->getListByType(Asset::Type::SOUND), &Resource::loadOneSound, LoadStage::MUSICS);
|
||||
break;
|
||||
}
|
||||
case LoadStage::MUSICS: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
if (stage_index_ == 0) { musics_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::TEXTURES;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneMusic(stage_index_++);
|
||||
advanceListLoadStage(Asset::get()->getListByType(Asset::Type::MUSIC), &Resource::loadOneMusic, LoadStage::TEXTURES);
|
||||
break;
|
||||
}
|
||||
case LoadStage::TEXTURES: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
if (stage_index_ == 0) { textures_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::TEXT_FILES;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneTexture(stage_index_++);
|
||||
advanceListLoadStage(Asset::get()->getListByType(Asset::Type::BITMAP), &Resource::loadOneTexture, LoadStage::TEXT_FILES);
|
||||
break;
|
||||
}
|
||||
case LoadStage::TEXT_FILES: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::FONT);
|
||||
if (stage_index_ == 0) { text_files_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::ANIMATIONS;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneTextFile(stage_index_++);
|
||||
advanceListLoadStage(Asset::get()->getListByType(Asset::Type::FONT), &Resource::loadOneTextFile, LoadStage::ANIMATIONS);
|
||||
break;
|
||||
}
|
||||
case LoadStage::ANIMATIONS: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::ANIMATION);
|
||||
if (stage_index_ == 0) { animations_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::DEMO_DATA;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneAnimation(stage_index_++);
|
||||
advanceListLoadStage(Asset::get()->getListByType(Asset::Type::ANIMATION), &Resource::loadOneAnimation, LoadStage::DEMO_DATA);
|
||||
break;
|
||||
}
|
||||
case LoadStage::DEMO_DATA: {
|
||||
auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
if (stage_index_ == 0) { demos_.clear(); }
|
||||
if (stage_index_ >= list.size()) {
|
||||
stage_ = LoadStage::CREATE_TEXT;
|
||||
stage_index_ = 0;
|
||||
break;
|
||||
}
|
||||
loadOneDemoData(stage_index_++);
|
||||
advanceListLoadStage(Asset::get()->getListByType(Asset::Type::DEMODATA), &Resource::loadOneDemoData, LoadStage::CREATE_TEXT);
|
||||
break;
|
||||
}
|
||||
case LoadStage::CREATE_TEXT:
|
||||
@@ -519,7 +486,7 @@ auto Resource::loadStep(int budget_ms) -> bool {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((SDL_GetTicksNS() - start_ns) >= budget_ns) { break; }
|
||||
if ((SDL_GetTicksNS() - START_NS) >= BUDGET_NS) { break; }
|
||||
}
|
||||
|
||||
return stage_ == LoadStage::DONE;
|
||||
@@ -542,11 +509,11 @@ void Resource::loadOneSound(size_t idx) {
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
auto audio_data = loadAudioData(path);
|
||||
JA_Sound_t* sound = nullptr;
|
||||
Ja::Sound* sound = nullptr;
|
||||
if (!audio_data.data.empty()) {
|
||||
sound = JA_LoadSound(audio_data.data.data(), audio_data.data.size());
|
||||
sound = Ja::loadSound(audio_data.data.data(), audio_data.data.size());
|
||||
} else {
|
||||
sound = JA_LoadSound(path.c_str());
|
||||
sound = Ja::loadSound(path.c_str());
|
||||
}
|
||||
if (sound == nullptr) {
|
||||
std::cout << "Sound load failed: " << name << '\n';
|
||||
@@ -561,11 +528,11 @@ void Resource::loadOneMusic(size_t idx) {
|
||||
auto name = getFileName(path);
|
||||
updateLoadingProgress(name);
|
||||
auto audio_data = loadAudioData(path);
|
||||
JA_Music_t* music = nullptr;
|
||||
Ja::Music* music = nullptr;
|
||||
if (!audio_data.data.empty()) {
|
||||
music = JA_LoadMusic(audio_data.data.data(), audio_data.data.size());
|
||||
music = Ja::loadMusic(audio_data.data.data(), audio_data.data.size());
|
||||
} else {
|
||||
music = JA_LoadMusic(path.c_str());
|
||||
music = Ja::loadMusic(path.c_str());
|
||||
}
|
||||
if (music == nullptr) {
|
||||
std::cout << "Music load failed: " << name << '\n';
|
||||
@@ -627,10 +594,10 @@ void Resource::createPlayerTextures() {
|
||||
const auto& player = players[player_idx]; // Obtenemos el jugador actual
|
||||
|
||||
// Encontrar el archivo original de la textura
|
||||
const auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto it = std::ranges::find_if(texture_list,
|
||||
const auto TEXTURE_LIST = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
const auto IT = std::ranges::find_if(TEXTURE_LIST,
|
||||
[&player](const auto& file) { return getFileName(file) == player.base_texture; });
|
||||
const std::string texture_file_path = (it != texture_list.end()) ? *it : std::string{};
|
||||
const std::string TEXTURE_FILE_PATH = (IT != TEXTURE_LIST.end()) ? *IT : std::string{};
|
||||
|
||||
// Crear las 4 texturas con sus respectivas paletas
|
||||
for (int palette_idx = 0; palette_idx < 4; ++palette_idx) {
|
||||
@@ -639,14 +606,14 @@ void Resource::createPlayerTextures() {
|
||||
if (palette_idx == 0) {
|
||||
// Textura 0 - usar la ya cargada y modificar solo paleta 0 (default_shirt)
|
||||
texture = getTexture(player.base_texture);
|
||||
texture->setPaletteColor(0, 16, param.player.default_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(0, 17, param.player.default_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(0, 18, param.player.default_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(0, 19, param.player.default_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(0, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
texture->setPaletteColor(0, 16, param.player.default_shirt[player_idx].darkest.toUint32());
|
||||
texture->setPaletteColor(0, 17, param.player.default_shirt[player_idx].dark.toUint32());
|
||||
texture->setPaletteColor(0, 18, param.player.default_shirt[player_idx].base.toUint32());
|
||||
texture->setPaletteColor(0, 19, param.player.default_shirt[player_idx].light.toUint32());
|
||||
texture->setPaletteColor(0, 56, param.player.outline_color[player_idx].toUint32());
|
||||
} else {
|
||||
// Crear textura nueva desde archivo usando ResourceHelper
|
||||
texture = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||
texture = std::make_shared<Texture>(Screen::get()->getRenderer(), TEXTURE_FILE_PATH);
|
||||
|
||||
// Añadir todas las paletas
|
||||
texture->addPaletteFromPalFile(Asset::get()->getPath(player.palette_files[0]));
|
||||
@@ -655,18 +622,18 @@ void Resource::createPlayerTextures() {
|
||||
|
||||
if (palette_idx == 1) {
|
||||
// Textura 1 - modificar solo paleta 1 (one_coffee_shirt)
|
||||
texture->setPaletteColor(1, 16, param.player.one_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(1, 17, param.player.one_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(1, 18, param.player.one_coffee_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(1, 19, param.player.one_coffee_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(1, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
texture->setPaletteColor(1, 16, param.player.one_coffee_shirt[player_idx].darkest.toUint32());
|
||||
texture->setPaletteColor(1, 17, param.player.one_coffee_shirt[player_idx].dark.toUint32());
|
||||
texture->setPaletteColor(1, 18, param.player.one_coffee_shirt[player_idx].base.toUint32());
|
||||
texture->setPaletteColor(1, 19, param.player.one_coffee_shirt[player_idx].light.toUint32());
|
||||
texture->setPaletteColor(1, 56, param.player.outline_color[player_idx].toUint32());
|
||||
} else if (palette_idx == 2) {
|
||||
// Textura 2 - modificar solo paleta 2 (two_coffee_shirt)
|
||||
texture->setPaletteColor(2, 16, param.player.two_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(2, 17, param.player.two_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(2, 18, param.player.two_coffee_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(2, 19, param.player.two_coffee_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(2, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
texture->setPaletteColor(2, 16, param.player.two_coffee_shirt[player_idx].darkest.toUint32());
|
||||
texture->setPaletteColor(2, 17, param.player.two_coffee_shirt[player_idx].dark.toUint32());
|
||||
texture->setPaletteColor(2, 18, param.player.two_coffee_shirt[player_idx].base.toUint32());
|
||||
texture->setPaletteColor(2, 19, param.player.two_coffee_shirt[player_idx].light.toUint32());
|
||||
texture->setPaletteColor(2, 56, param.player.outline_color[player_idx].toUint32());
|
||||
}
|
||||
// Textura 3 (palette_idx == 3) - no modificar nada, usar colores originales
|
||||
}
|
||||
@@ -769,7 +736,7 @@ void Resource::createText() {
|
||||
void Resource::clearSounds() {
|
||||
for (auto& sound : sounds_) {
|
||||
if (sound.sound != nullptr) {
|
||||
JA_DeleteSound(sound.sound);
|
||||
Ja::deleteSound(sound.sound);
|
||||
sound.sound = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -780,7 +747,7 @@ void Resource::clearSounds() {
|
||||
void Resource::clearMusics() {
|
||||
for (auto& music : musics_) {
|
||||
if (music.music != nullptr) {
|
||||
JA_DeleteMusic(music.music);
|
||||
Ja::deleteMusic(music.music);
|
||||
music.music = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -830,7 +797,7 @@ void Resource::renderProgress() {
|
||||
const bool WAITING_FOR_INPUT = isLoadDone() && Options::loading.wait_for_input;
|
||||
|
||||
auto text_color = param.resource.color;
|
||||
auto bar_color = param.resource.color.DARKEN(100);
|
||||
auto bar_color = param.resource.color.darken(100);
|
||||
const auto TEXT_HEIGHT = loading_text_->getCharacterSize();
|
||||
|
||||
// Dibuja el interior de la barra de progreso
|
||||
@@ -880,10 +847,10 @@ void Resource::renderProgress() {
|
||||
|
||||
// Carga los datos para el modo demostración (sin mostrar progreso)
|
||||
void Resource::loadDemoDataQuiet() {
|
||||
const auto list = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
const auto LIST = Asset::get()->getListByType(Asset::Type::DEMODATA);
|
||||
demos_.clear();
|
||||
demos_.reserve(list.size());
|
||||
std::ranges::transform(list, std::back_inserter(demos_), [this](const auto& l) { return loadDemoDataFromFile(l); });
|
||||
demos_.reserve(LIST.size());
|
||||
std::ranges::transform(LIST, std::back_inserter(demos_), [](const auto& l) { return loadDemoDataFromFile(l); });
|
||||
}
|
||||
|
||||
// Inicializa los rectangulos que definen la barra de progreso
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <utility> // Para move
|
||||
@@ -13,14 +14,16 @@
|
||||
#include "core/rendering/texture.hpp" // Para Texture
|
||||
#include "core/system/demo.hpp" // Para DemoData
|
||||
|
||||
struct JA_Music_t;
|
||||
struct JA_Sound_t;
|
||||
namespace Ja {
|
||||
struct Music;
|
||||
struct Sound;
|
||||
} // namespace Ja
|
||||
|
||||
// --- Clase Resource: gestiona todos los recursos del juego (singleton) ---
|
||||
class Resource {
|
||||
public:
|
||||
// --- Enum para el modo de carga ---
|
||||
enum class LoadingMode {
|
||||
enum class LoadingMode : std::uint8_t {
|
||||
PRELOAD, // Carga todos los recursos al inicio
|
||||
LAZY_LOAD // Carga los recursos bajo demanda
|
||||
};
|
||||
@@ -31,8 +34,8 @@ class Resource {
|
||||
static auto get() -> Resource*; // Obtiene el puntero al objeto Resource
|
||||
|
||||
// --- Métodos de acceso a recursos ---
|
||||
auto getSound(const std::string& name) -> JA_Sound_t*; // Obtiene el sonido por nombre
|
||||
auto getMusic(const std::string& name) -> JA_Music_t*; // Obtiene la música por nombre
|
||||
auto getSound(const std::string& name) -> Ja::Sound*; // Obtiene el sonido por nombre
|
||||
auto getMusic(const std::string& name) -> Ja::Music*; // Obtiene la música por nombre
|
||||
auto getTexture(const std::string& name) -> std::shared_ptr<Texture>; // Obtiene la textura por nombre
|
||||
auto getTextFile(const std::string& name) -> std::shared_ptr<Text::File>; // Obtiene el fichero de texto por nombre
|
||||
auto getText(const std::string& name) -> std::shared_ptr<Text>; // Obtiene el objeto de texto por nombre
|
||||
@@ -58,18 +61,18 @@ class Resource {
|
||||
// --- Estructuras para recursos individuales ---
|
||||
struct ResourceSound {
|
||||
std::string name; // Nombre del sonido
|
||||
JA_Sound_t* sound; // Objeto con el sonido
|
||||
Ja::Sound* sound; // Objeto con el sonido
|
||||
|
||||
explicit ResourceSound(std::string name, JA_Sound_t* sound = nullptr)
|
||||
explicit ResourceSound(std::string name, Ja::Sound* sound = nullptr)
|
||||
: name(std::move(name)),
|
||||
sound(sound) {}
|
||||
};
|
||||
|
||||
struct ResourceMusic {
|
||||
std::string name; // Nombre de la música
|
||||
JA_Music_t* music; // Objeto con la música
|
||||
Ja::Music* music; // Objeto con la música
|
||||
|
||||
explicit ResourceMusic(std::string name, JA_Music_t* music = nullptr)
|
||||
explicit ResourceMusic(std::string name, Ja::Music* music = nullptr)
|
||||
: name(std::move(name)),
|
||||
music(music) {}
|
||||
};
|
||||
@@ -156,7 +159,7 @@ class Resource {
|
||||
SDL_FRect loading_full_rect_;
|
||||
|
||||
// --- Estado del cargador incremental ---
|
||||
enum class LoadStage {
|
||||
enum class LoadStage : std::uint8_t {
|
||||
SOUNDS,
|
||||
MUSICS,
|
||||
TEXTURES,
|
||||
@@ -187,8 +190,8 @@ class Resource {
|
||||
|
||||
// --- Métodos para carga perezosa ---
|
||||
void initResourceLists(); // Inicializa las listas de recursos sin cargar el contenido
|
||||
static auto loadSoundLazy(const std::string& name) -> JA_Sound_t*; // Carga un sonido específico bajo demanda
|
||||
static auto loadMusicLazy(const std::string& name) -> JA_Music_t*; // Carga una música específica bajo demanda
|
||||
static auto loadSoundLazy(const std::string& name) -> Ja::Sound*; // Carga un sonido específico bajo demanda
|
||||
static auto loadMusicLazy(const std::string& name) -> Ja::Music*; // Carga una música específica bajo demanda
|
||||
static auto loadTextureLazy(const std::string& name) -> std::shared_ptr<Texture>; // Carga una textura específica bajo demanda
|
||||
static auto loadTextFileLazy(const std::string& name) -> std::shared_ptr<Text::File>; // Carga un fichero de texto específico bajo demanda
|
||||
auto loadTextLazy(const std::string& name) -> std::shared_ptr<Text>; // Carga un objeto de texto específico bajo demanda
|
||||
@@ -200,6 +203,10 @@ class Resource {
|
||||
void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso
|
||||
void updateProgressBar(); // Actualiza la barra de estado
|
||||
|
||||
// Avança una etapa que descarrega una llista d'assets: si `stage_index_` desborda la mida,
|
||||
// salta a `next_stage`; si no, crida `load_one` per a l'element actual i incrementa.
|
||||
void advanceListLoadStage(const std::vector<std::string>& list, void (Resource::*load_one)(size_t), LoadStage next_stage);
|
||||
|
||||
// --- Helpers del cargador incremental (cargan un único recurso) ---
|
||||
void loadOneSound(size_t idx);
|
||||
void loadOneMusic(size_t idx);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "core/resources/resource_helper.hpp" // Para ResourceHelper
|
||||
#include "utils/utils.hpp" // Para getFileName
|
||||
|
||||
// Carga el fichero de datos para la demo
|
||||
auto loadDemoDataFromFile(const std::string& file_path) -> DemoData {
|
||||
|
||||
@@ -38,6 +38,38 @@
|
||||
#include "game/ui/service_menu.hpp" // Para ServiceMenu
|
||||
#include "utils/param.hpp" // Para loadParamsFromFile
|
||||
|
||||
namespace {
|
||||
// Llig un camp opcional d'un YAML cap a `dest`. Si no existeix, no toca `dest`.
|
||||
// Si existeix però el tipus no encaixa, deixa el valor per defecte i avisa per stderr
|
||||
// (un debug.yaml mal escrit no ha de tombar l'arrencada, però l'usuari ha de saber-ho).
|
||||
template <typename T>
|
||||
void loadYamlField(const fkyaml::node& yaml, const std::string& key, T& dest) {
|
||||
if (!yaml.contains(key)) { return; }
|
||||
try {
|
||||
dest = yaml[key].get_value<T>();
|
||||
} catch (...) {
|
||||
std::cerr << "debug.yaml: valor invàlid per a '" << key << "', es manté el valor per defecte\n";
|
||||
}
|
||||
}
|
||||
|
||||
auto parseInitialSection(const std::string& value) -> Section::Name {
|
||||
if (value == "logo") { return Section::Name::LOGO; }
|
||||
if (value == "intro") { return Section::Name::INTRO; }
|
||||
if (value == "title") { return Section::Name::TITLE; }
|
||||
if (value == "credits") { return Section::Name::CREDITS; }
|
||||
if (value == "instructions") { return Section::Name::INSTRUCTIONS; }
|
||||
if (value == "hiscore") { return Section::Name::HI_SCORE_TABLE; }
|
||||
return Section::Name::GAME; // "game" i qualsevol valor desconegut
|
||||
}
|
||||
|
||||
auto parseInitialOptions(const std::string& value) -> Section::Options {
|
||||
if (value == "none") { return Section::Options::NONE; }
|
||||
if (value == "2p") { return Section::Options::GAME_PLAY_2P; }
|
||||
if (value == "both") { return Section::Options::GAME_PLAY_BOTH; }
|
||||
return Section::Options::GAME_PLAY_1P; // "1p" i qualsevol valor desconegut
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Constructor
|
||||
Director::Director() {
|
||||
Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO;
|
||||
@@ -275,78 +307,20 @@ void Director::loadDebugConfig() {
|
||||
file.close();
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(content);
|
||||
if (yaml.contains("initial_section")) {
|
||||
try {
|
||||
debug_config.initial_section = yaml["initial_section"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (yaml.contains("initial_options")) {
|
||||
try {
|
||||
debug_config.initial_options = yaml["initial_options"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (yaml.contains("initial_stage")) {
|
||||
try {
|
||||
debug_config.initial_stage = yaml["initial_stage"].get_value<int>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (yaml.contains("show_render_info")) {
|
||||
try {
|
||||
debug_config.show_render_info = yaml["show_render_info"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (yaml.contains("resource_loading")) {
|
||||
try {
|
||||
debug_config.resource_loading = yaml["resource_loading"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (yaml.contains("autoplay")) {
|
||||
try {
|
||||
debug_config.autoplay = yaml["autoplay"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (yaml.contains("invincibility")) {
|
||||
try {
|
||||
debug_config.invincibility = yaml["invincibility"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
loadYamlField(yaml, "initial_section", debug_config.initial_section);
|
||||
loadYamlField(yaml, "initial_options", debug_config.initial_options);
|
||||
loadYamlField(yaml, "initial_stage", debug_config.initial_stage);
|
||||
loadYamlField(yaml, "show_render_info", debug_config.show_render_info);
|
||||
loadYamlField(yaml, "resource_loading", debug_config.resource_loading);
|
||||
loadYamlField(yaml, "autoplay", debug_config.autoplay);
|
||||
loadYamlField(yaml, "invincibility", debug_config.invincibility);
|
||||
} catch (...) {
|
||||
std::cout << "Error parsing debug.yaml, using defaults" << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
// Mapear strings a enums
|
||||
const auto& sec = debug_config.initial_section;
|
||||
if (sec == "logo") {
|
||||
Section::name = Section::Name::LOGO;
|
||||
} else if (sec == "intro") {
|
||||
Section::name = Section::Name::INTRO;
|
||||
} else if (sec == "title") {
|
||||
Section::name = Section::Name::TITLE;
|
||||
} else if (sec == "game") {
|
||||
Section::name = Section::Name::GAME;
|
||||
} else if (sec == "credits") {
|
||||
Section::name = Section::Name::CREDITS;
|
||||
} else if (sec == "instructions") {
|
||||
Section::name = Section::Name::INSTRUCTIONS;
|
||||
} else if (sec == "hiscore") {
|
||||
Section::name = Section::Name::HI_SCORE_TABLE;
|
||||
} else {
|
||||
Section::name = Section::Name::GAME;
|
||||
}
|
||||
|
||||
const auto& opt = debug_config.initial_options;
|
||||
if (opt == "none") {
|
||||
Section::options = Section::Options::NONE;
|
||||
} else if (opt == "1p") {
|
||||
Section::options = Section::Options::GAME_PLAY_1P;
|
||||
} else if (opt == "2p") {
|
||||
Section::options = Section::Options::GAME_PLAY_2P;
|
||||
} else if (opt == "both") {
|
||||
Section::options = Section::Options::GAME_PLAY_BOTH;
|
||||
} else {
|
||||
Section::options = Section::Options::GAME_PLAY_1P;
|
||||
}
|
||||
Section::name = parseInitialSection(debug_config.initial_section);
|
||||
Section::options = parseInitialOptions(debug_config.initial_options);
|
||||
}
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
@@ -499,7 +473,7 @@ auto Director::iterate() -> SDL_AppResult {
|
||||
|
||||
// Ejecuta un frame de la sección activa
|
||||
if (preload_) {
|
||||
preload_->iterate();
|
||||
Preload::iterate();
|
||||
} else if (logo_) {
|
||||
logo_->iterate();
|
||||
} else if (intro_) {
|
||||
@@ -526,7 +500,7 @@ auto Director::handleEvent(const SDL_Event& event) -> SDL_AppResult {
|
||||
|
||||
// Reenvía a la sección activa
|
||||
if (preload_) {
|
||||
preload_->handleEvent(event);
|
||||
Preload::handleEvent(event);
|
||||
} else if (logo_) {
|
||||
logo_->handleEvent(event);
|
||||
} else if (intro_) {
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
|
||||
#include "core/system/section.hpp" // Para Section::Name
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
|
||||
namespace Lang {
|
||||
enum class Code : int;
|
||||
enum class Code : std::uint8_t;
|
||||
}
|
||||
|
||||
// Declaraciones adelantadas de las secciones
|
||||
@@ -70,7 +72,7 @@ class Director {
|
||||
|
||||
// --- Inicialización y cierre del sistema ---
|
||||
void init(); // Inicializa la aplicación (pre-boot)
|
||||
void finishBoot(); // Post-boot: inicializa lo que depende de recursos cargados
|
||||
static void finishBoot(); // Post-boot: inicializa lo que depende de recursos cargados
|
||||
static void close(); // Cierra y libera recursos
|
||||
|
||||
// --- Configuración inicial ---
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/*
|
||||
Namespace section: define los estados/secciones principales del programa,
|
||||
así como las opciones y modos especiales (como el Attract Mode).
|
||||
@@ -8,7 +10,7 @@
|
||||
|
||||
namespace Section {
|
||||
// --- Enumeraciones de secciones del programa ---
|
||||
enum class Name {
|
||||
enum class Name : std::uint8_t {
|
||||
RESET, // Inicialización
|
||||
PRELOAD, // Carga incremental de recursos
|
||||
LOGO, // Pantalla de logo
|
||||
@@ -23,7 +25,7 @@ namespace Section {
|
||||
};
|
||||
|
||||
// --- Opciones para la sección actual ---
|
||||
enum class Options {
|
||||
enum class Options : std::uint8_t {
|
||||
GAME_PLAY_1P, // Iniciar el juego con el jugador 1
|
||||
GAME_PLAY_2P, // Iniciar el juego con el jugador 2
|
||||
GAME_PLAY_BOTH, // Iniciar el juego con los dos jugadores
|
||||
@@ -37,7 +39,7 @@ namespace Section {
|
||||
};
|
||||
|
||||
// --- Modos para el Attract Mode ---
|
||||
enum class AttractMode {
|
||||
enum class AttractMode : std::uint8_t {
|
||||
TITLE_TO_DEMO, // Pasar de título a demo
|
||||
TITLE_TO_LOGO, // Pasar de título a logo
|
||||
};
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// --- Namespace SystemShutdown: utilidad multiplataforma para apagar el sistema de forma segura ---
|
||||
namespace SystemShutdown {
|
||||
|
||||
// --- Enums ---
|
||||
enum class ShutdownResult {
|
||||
enum class ShutdownResult : std::uint8_t {
|
||||
SUCCESS = 0, // Éxito
|
||||
ERROR_PERMISSION, // Error de permisos insuficientes
|
||||
ERROR_SYSTEM_CALL, // Error en la llamada al sistema
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
// --- Namespace SystemUtils: utilidades multiplataforma para operaciones del sistema ---
|
||||
namespace SystemUtils {
|
||||
// --- Enums ---
|
||||
enum class Result { // Códigos de resultado para operaciones del sistema
|
||||
enum class Result : std::uint8_t { // Códigos de resultado para operaciones del sistema
|
||||
SUCCESS = 0,
|
||||
PERMISSION_DENIED, // Sin permisos para crear la carpeta
|
||||
PATH_TOO_LONG, // Ruta demasiado larga
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||
#include "core/rendering/sprite/sprite.hpp" // Para Sprite
|
||||
#include "core/rendering/texture.hpp" // Para Texture
|
||||
#include "core/rendering/texture.hpp" // IWYU pragma: keep
|
||||
#include "utils/param.hpp" // Para Param, ParamBalloon, param
|
||||
|
||||
// Constructor
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect, Uint16
|
||||
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||
#include "utils/utils.hpp" // Para Circle
|
||||
@@ -12,7 +13,7 @@
|
||||
class Texture;
|
||||
|
||||
// --- Enums ---
|
||||
enum class ItemType : int {
|
||||
enum class ItemType : std::uint8_t {
|
||||
DISK = 1, // Disco
|
||||
GAVINA = 2, // Gavina
|
||||
PACMAR = 3, // Pacman
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/input/input_types.hpp" // Para InputAction
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||
#include "core/rendering/texture.hpp" // Para Texture
|
||||
#include "core/resources/asset.hpp" // Para Asset
|
||||
@@ -1135,8 +1134,6 @@ void Player::updateFiringStateFromVisual() {
|
||||
firing_state_ = State::RECOILING_RIGHT;
|
||||
break;
|
||||
case State::FIRING_UP:
|
||||
firing_state_ = State::RECOILING_UP;
|
||||
break;
|
||||
default:
|
||||
firing_state_ = State::RECOILING_UP;
|
||||
break;
|
||||
@@ -1152,8 +1149,6 @@ void Player::updateFiringStateFromVisual() {
|
||||
firing_state_ = State::COOLING_RIGHT;
|
||||
break;
|
||||
case State::FIRING_UP:
|
||||
firing_state_ = State::COOLING_UP;
|
||||
break;
|
||||
default:
|
||||
firing_state_ = State::COOLING_UP;
|
||||
break;
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_FlipMode
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <iterator> // Para pair
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para basic_string, string
|
||||
#include <utility> // Para move, pair
|
||||
#include <vector> // Para vector
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t, std::int8_t
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para basic_string, string
|
||||
#include <utility> // Para move, pair
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/input/input.hpp" // for Input
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // for AnimatedSprite
|
||||
@@ -49,14 +49,14 @@ class Player {
|
||||
};
|
||||
|
||||
// --- Enums ---
|
||||
enum class Id : int {
|
||||
enum class Id : std::int8_t {
|
||||
NO_PLAYER = -1, // Sin jugador
|
||||
BOTH_PLAYERS = 0, // Ambos jugadores
|
||||
PLAYER1 = 1, // Jugador 1
|
||||
PLAYER2 = 2 // Jugador 2
|
||||
};
|
||||
|
||||
enum class State {
|
||||
enum class State : std::uint8_t {
|
||||
// Estados de movimiento
|
||||
WALKING_LEFT, // Caminando hacia la izquierda
|
||||
WALKING_RIGHT, // Caminando hacia la derecha
|
||||
@@ -293,7 +293,7 @@ class Player {
|
||||
bool can_fire_new_system_ = true; // true si puede disparar ahora mismo
|
||||
|
||||
// LÍNEA 2: SISTEMA VISUAL (Animaciones)
|
||||
enum class VisualFireState {
|
||||
enum class VisualFireState : std::uint8_t {
|
||||
NORMAL, // Brazo en posición neutral
|
||||
AIMING, // Brazo alzado (disparando)
|
||||
RECOILING, // Brazo en retroceso
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para Uint32, SDL_GetTicks, SDL_FRect
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <cstdlib> // Para rand
|
||||
#include <memory> // Para unique_ptr
|
||||
|
||||
@@ -11,12 +12,12 @@
|
||||
class Tabe {
|
||||
public:
|
||||
// --- Enumeraciones para dirección y estado ---
|
||||
enum class Direction : int {
|
||||
enum class Direction : std::uint8_t {
|
||||
TO_THE_LEFT = 0,
|
||||
TO_THE_RIGHT = 1,
|
||||
};
|
||||
|
||||
enum class State : int {
|
||||
enum class State : std::uint8_t {
|
||||
FLY = 0,
|
||||
HIT = 1,
|
||||
};
|
||||
|
||||
@@ -201,6 +201,8 @@ auto BalloonFormations::evaluateSimpleExpression(const std::string& expr, const
|
||||
return left_val * right_val;
|
||||
case '/':
|
||||
return right_val != 0 ? left_val / right_val : 0;
|
||||
default:
|
||||
break; // Inalcanzable: el if exterior solo deja pasar '+', '-', '*', '/'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <iterator> // Para pair
|
||||
#include <map> // Para map
|
||||
#include <optional> // Para optional
|
||||
#include <string> // Para string
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "game/gameplay/bullet_manager.hpp"
|
||||
|
||||
#include <algorithm> // Para remove_if
|
||||
#include <utility>
|
||||
|
||||
#include "game/entities/bullet.hpp" // Para Bullet
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <functional> // Para function
|
||||
#include <list> // Para list
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "game/entities/bullet.hpp" // for Bullet
|
||||
|
||||
|
||||
@@ -19,19 +19,19 @@ namespace Difficulty {
|
||||
}
|
||||
|
||||
auto getNameFromCode(Code code) -> std::string {
|
||||
const auto it = std::ranges::find_if(difficulties_list,
|
||||
const auto IT = std::ranges::find_if(difficulties_list,
|
||||
[code](const auto& difficulty) { return difficulty.code == code; });
|
||||
if (it != difficulties_list.end()) {
|
||||
return it->name;
|
||||
if (IT != difficulties_list.end()) {
|
||||
return IT->name;
|
||||
}
|
||||
return !difficulties_list.empty() ? difficulties_list.front().name : "Unknown";
|
||||
}
|
||||
|
||||
auto getCodeFromName(const std::string& name) -> Code {
|
||||
const auto it = std::ranges::find_if(difficulties_list,
|
||||
const auto IT = std::ranges::find_if(difficulties_list,
|
||||
[&name](const auto& difficulty) { return difficulty.name == name; });
|
||||
if (it != difficulties_list.end()) {
|
||||
return it->code;
|
||||
if (IT != difficulties_list.end()) {
|
||||
return IT->code;
|
||||
}
|
||||
return !difficulties_list.empty() ? difficulties_list.front().code : Code::NORMAL;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
namespace Difficulty {
|
||||
|
||||
// --- Enums ---
|
||||
enum class Code {
|
||||
enum class Code : std::uint8_t {
|
||||
EASY = 0, // Dificultad fácil
|
||||
NORMAL = 1, // Dificultad normal
|
||||
HARD = 2, // Dificultad difícil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para unique_ptr, shared_ptr
|
||||
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
||||
#include "core/rendering/sprite/smart_sprite.hpp" // Para SmartSprite
|
||||
@@ -36,7 +37,7 @@ class GameLogo {
|
||||
|
||||
private:
|
||||
// --- Enums ---
|
||||
enum class Status {
|
||||
enum class Status : std::uint8_t {
|
||||
DISABLED, // Deshabilitado
|
||||
MOVING, // En movimiento
|
||||
SHAKING, // Temblando
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_ReadIO, SDL_WriteIO, SDL_CloseIO, SDL_GetError, SDL_IOFromFile, SDL_LogError, SDL_LogCategory, SDL_LogInfo
|
||||
|
||||
#include <algorithm> // Para __sort_fn, sort
|
||||
#include <array> // Para array
|
||||
#include <functional> // Para identity
|
||||
#include <iomanip> // Para std::setw, std::setfill
|
||||
#include <iostream> // Para std::cout
|
||||
#include <iterator> // Para distance
|
||||
#include <numeric> // Para accumulate
|
||||
#include <ranges> // Para __find_if_fn, find_if
|
||||
#include <utility> // Para move
|
||||
#include <algorithm> // Para sort, ranges::find_if, ranges::sort
|
||||
#include <array> // Para array
|
||||
#include <iomanip> // Para std::setw, std::setfill
|
||||
#include <iostream> // Para std::cout
|
||||
#include <iterator> // Para distance
|
||||
#include <numeric> // Para accumulate
|
||||
#include <utility> // Para move
|
||||
|
||||
#include "utils/utils.hpp" // Para getFileName
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ Scoreboard::Scoreboard()
|
||||
fillBackgroundTexture();
|
||||
|
||||
// Inicializa el ciclo de colores para el nombre
|
||||
name_color_cycle_ = Colors::generateMirroredCycle(color_.INVERSE(), ColorCycleStyle::VIBRANT);
|
||||
name_color_cycle_ = Colors::generateMirroredCycle(color_.inverse(), ColorCycleStyle::VIBRANT);
|
||||
animated_color_ = name_color_cycle_.at(0);
|
||||
}
|
||||
|
||||
@@ -337,13 +337,13 @@ void Scoreboard::render() {
|
||||
void Scoreboard::setColor(Color color) {
|
||||
// Actualiza las variables de colores
|
||||
color_ = color;
|
||||
text_color1_ = param.scoreboard.text_autocolor ? color_.LIGHTEN(100) : param.scoreboard.text_color1;
|
||||
text_color2_ = param.scoreboard.text_autocolor ? color_.LIGHTEN(150) : param.scoreboard.text_color2;
|
||||
text_color1_ = param.scoreboard.text_autocolor ? color_.lighten(100) : param.scoreboard.text_color1;
|
||||
text_color2_ = param.scoreboard.text_autocolor ? color_.lighten(150) : param.scoreboard.text_color2;
|
||||
|
||||
// Aplica los colores
|
||||
power_meter_sprite_->getTexture()->setColor(text_color2_);
|
||||
fillBackgroundTexture();
|
||||
name_color_cycle_ = Colors::generateMirroredCycle(color_.INVERSE(), ColorCycleStyle::VIBRANT);
|
||||
name_color_cycle_ = Colors::generateMirroredCycle(color_.inverse(), ColorCycleStyle::VIBRANT);
|
||||
}
|
||||
|
||||
// Establece el valor de la variable
|
||||
@@ -383,9 +383,9 @@ void Scoreboard::fillPanelTextures() {
|
||||
}
|
||||
|
||||
// Interpolar entre color base y color aclarado
|
||||
Color target_color = color_.LIGHTEN(PANEL_PULSE_LIGHTEN_AMOUNT);
|
||||
Color target_color = color_.lighten(PANEL_PULSE_LIGHTEN_AMOUNT);
|
||||
// Color target_color = color_.INVERSE();
|
||||
background_color = color_.LERP(target_color, pulse_intensity);
|
||||
background_color = color_.lerp(target_color, pulse_intensity);
|
||||
background_color.a = 255; // Opaco durante el pulso
|
||||
}
|
||||
|
||||
@@ -716,7 +716,7 @@ void Scoreboard::createPanelTextures() {
|
||||
// Dibuja la linea que separa la zona de juego del marcador
|
||||
void Scoreboard::renderSeparator() {
|
||||
// Dibuja la linea que separa el marcador de la zona de juego
|
||||
auto color = param.scoreboard.separator_autocolor ? color_.DARKEN() : param.scoreboard.separator_color;
|
||||
auto color = param.scoreboard.separator_autocolor ? color_.darken() : param.scoreboard.separator_color;
|
||||
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255);
|
||||
SDL_RenderLine(renderer_, 0, 0, rect_.w, 0);
|
||||
}
|
||||
@@ -755,7 +755,7 @@ void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
||||
}
|
||||
|
||||
const float FRACTIONAL_OFFSET = frac;
|
||||
const int PIXEL_OFFSET = static_cast<int>((FRACTIONAL_OFFSET * CHAR_STEP) + 0.5F);
|
||||
const int PIXEL_OFFSET = static_cast<int>(std::lround(FRACTIONAL_OFFSET * CHAR_STEP));
|
||||
|
||||
// Índice base en la lista de caracteres (posición central)
|
||||
const int BASE_INDEX = static_cast<int>(std::floor(carousel_pos));
|
||||
@@ -790,13 +790,13 @@ void Scoreboard::renderCarousel(size_t panel_index, int center_x, int y) {
|
||||
if (DISTANCE_FROM_CENTER < 0.5F) {
|
||||
// Letra central → transiciona hacia animated_color_
|
||||
float lerp_to_animated = DISTANCE_FROM_CENTER / 0.5F; // 0.0 a 1.0
|
||||
letter_color = animated_color_.LERP(text_color1_, lerp_to_animated);
|
||||
letter_color = animated_color_.lerp(text_color1_, lerp_to_animated);
|
||||
} else {
|
||||
// Letras alejadas → degradan hacia color_ base
|
||||
float base_lerp = (DISTANCE_FROM_CENTER - 0.5F) / (HALF_VISIBLE - 0.5F);
|
||||
base_lerp = std::min(base_lerp, 1.0F);
|
||||
const float LERP_FACTOR = base_lerp * 0.85F;
|
||||
letter_color = text_color1_.LERP(color_, LERP_FACTOR);
|
||||
letter_color = text_color1_.lerp(color_, LERP_FACTOR);
|
||||
}
|
||||
|
||||
// Calcular posición X de la letra
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <array> // Para array
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
@@ -21,14 +22,14 @@ class Texture;
|
||||
class Scoreboard {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Id : size_t {
|
||||
enum class Id : std::uint8_t {
|
||||
LEFT = 0,
|
||||
CENTER = 1,
|
||||
RIGHT = 2,
|
||||
SIZE = 3
|
||||
};
|
||||
|
||||
enum class Mode : int {
|
||||
enum class Mode : std::uint8_t {
|
||||
SCORE,
|
||||
STAGE_INFO,
|
||||
CONTINUE,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <functional> // Para function
|
||||
#include <optional> // Para optional
|
||||
#include <string> // Para basic_string, string
|
||||
@@ -9,12 +10,12 @@
|
||||
#include "core/system/stage_interface.hpp" // for IStageInfo
|
||||
|
||||
// --- Enums ---
|
||||
enum class PowerCollectionState {
|
||||
enum class PowerCollectionState : std::uint8_t {
|
||||
ENABLED, // Recolección habilitada
|
||||
DISABLED // Recolección deshabilitada
|
||||
};
|
||||
|
||||
enum class StageStatus {
|
||||
enum class StageStatus : std::uint8_t {
|
||||
LOCKED, // Fase bloqueada
|
||||
IN_PROGRESS, // Fase en progreso
|
||||
COMPLETED // Fase completada
|
||||
|
||||
+120
-235
@@ -26,12 +26,12 @@ namespace Options {
|
||||
Keyboard keyboard; // Opciones para el teclado
|
||||
PendingChanges pending_changes; // Opciones que se aplican al cerrar
|
||||
std::vector<PostFXPreset> postfx_presets = {
|
||||
{"CRT", 0.15F, 0.7F, 0.2F, 0.5F, 0.1F, 0.0F, 0.0F, 0.0F},
|
||||
{"NTSC", 0.4F, 0.5F, 0.2F, 0.3F, 0.3F, 0.0F, 0.6F, 0.0F},
|
||||
{"Curved", 0.5F, 0.6F, 0.1F, 0.4F, 0.4F, 0.8F, 0.0F, 0.0F},
|
||||
{"Scanlines", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F},
|
||||
{"Subtle", 0.3F, 0.4F, 0.05F, 0.0F, 0.2F, 0.0F, 0.0F, 0.0F},
|
||||
{"CRT Live", 0.15F, 0.6F, 0.3F, 0.3F, 0.1F, 0.0F, 0.4F, 0.8F},
|
||||
{.name = "CRT", .vignette = 0.15F, .scanlines = 0.7F, .chroma = 0.2F, .mask = 0.5F, .gamma = 0.1F, .curvature = 0.0F, .bleeding = 0.0F, .flicker = 0.0F},
|
||||
{.name = "NTSC", .vignette = 0.4F, .scanlines = 0.5F, .chroma = 0.2F, .mask = 0.3F, .gamma = 0.3F, .curvature = 0.0F, .bleeding = 0.6F, .flicker = 0.0F},
|
||||
{.name = "Curved", .vignette = 0.5F, .scanlines = 0.6F, .chroma = 0.1F, .mask = 0.4F, .gamma = 0.4F, .curvature = 0.8F, .bleeding = 0.0F, .flicker = 0.0F},
|
||||
{.name = "Scanlines", .vignette = 0.0F, .scanlines = 0.8F, .chroma = 0.0F, .mask = 0.0F, .gamma = 0.0F, .curvature = 0.0F, .bleeding = 0.0F, .flicker = 0.0F},
|
||||
{.name = "Subtle", .vignette = 0.3F, .scanlines = 0.4F, .chroma = 0.05F, .mask = 0.0F, .gamma = 0.2F, .curvature = 0.0F, .bleeding = 0.0F, .flicker = 0.0F},
|
||||
{.name = "CRT Live", .vignette = 0.15F, .scanlines = 0.6F, .chroma = 0.3F, .mask = 0.3F, .gamma = 0.1F, .curvature = 0.0F, .bleeding = 0.4F, .flicker = 0.8F},
|
||||
};
|
||||
std::string postfx_file_path;
|
||||
std::vector<CrtPiPreset> crtpi_presets;
|
||||
@@ -50,11 +50,17 @@ namespace Options {
|
||||
void setCrtPiFile(const std::string& path) { crtpi_file_path = path; }
|
||||
|
||||
// Helper: extrae un campo float de un nodo YAML si existe, ignorando errores de conversión
|
||||
static void parseFloatField(const fkyaml::node& node, const std::string& key, float& target) {
|
||||
if (node.contains(key)) {
|
||||
try {
|
||||
target = node[key].get_value<float>();
|
||||
} catch (...) {}
|
||||
// Llig un camp opcional d'un node YAML. Si no existeix, no toca `target`.
|
||||
// Si existeix però el tipus no encaixa, manté el valor previ i avisa per stderr
|
||||
// (un fitxer de configuració parcialment malformat no ha de tombar l'arrencada,
|
||||
// però l'usuari ha de saber quin camp ha quedat ignorat).
|
||||
template <typename T>
|
||||
void parseField(const fkyaml::node& node, const std::string& key, T& target) {
|
||||
if (!node.contains(key)) { return; }
|
||||
try {
|
||||
target = node[key].get_value<T>();
|
||||
} catch (...) {
|
||||
std::cerr << "config YAML: valor invàlid per a '" << key << "', es manté el valor per defecte\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,14 +86,14 @@ namespace Options {
|
||||
if (p.contains("name")) {
|
||||
preset.name = p["name"].get_value<std::string>();
|
||||
}
|
||||
parseFloatField(p, "vignette", preset.vignette);
|
||||
parseFloatField(p, "scanlines", preset.scanlines);
|
||||
parseFloatField(p, "chroma", preset.chroma);
|
||||
parseFloatField(p, "mask", preset.mask);
|
||||
parseFloatField(p, "gamma", preset.gamma);
|
||||
parseFloatField(p, "curvature", preset.curvature);
|
||||
parseFloatField(p, "bleeding", preset.bleeding);
|
||||
parseFloatField(p, "flicker", preset.flicker);
|
||||
parseField(p, "vignette", preset.vignette);
|
||||
parseField(p, "scanlines", preset.scanlines);
|
||||
parseField(p, "chroma", preset.chroma);
|
||||
parseField(p, "mask", preset.mask);
|
||||
parseField(p, "gamma", preset.gamma);
|
||||
parseField(p, "curvature", preset.curvature);
|
||||
parseField(p, "bleeding", preset.bleeding);
|
||||
parseField(p, "flicker", preset.flicker);
|
||||
postfx_presets.push_back(preset);
|
||||
}
|
||||
}
|
||||
@@ -212,24 +218,6 @@ namespace Options {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper: extrae un campo bool de un nodo YAML si existe, ignorando errores
|
||||
static void parseBoolField(const fkyaml::node& node, const std::string& key, bool& target) {
|
||||
if (node.contains(key)) {
|
||||
try {
|
||||
target = node[key].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: extrae un campo int de un nodo YAML si existe, ignorando errores
|
||||
static void parseIntField(const fkyaml::node& node, const std::string& key, int& target) {
|
||||
if (node.contains(key)) {
|
||||
try {
|
||||
target = node[key].get_value<int>();
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
// Rellena los presets CrtPi por defecto
|
||||
static void populateDefaultCrtPiPresets() {
|
||||
crtpi_presets.clear();
|
||||
@@ -289,20 +277,20 @@ namespace Options {
|
||||
if (p.contains("name")) {
|
||||
preset.name = p["name"].get_value<std::string>();
|
||||
}
|
||||
parseFloatField(p, "scanline_weight", preset.scanline_weight);
|
||||
parseFloatField(p, "scanline_gap_brightness", preset.scanline_gap_brightness);
|
||||
parseFloatField(p, "bloom_factor", preset.bloom_factor);
|
||||
parseFloatField(p, "input_gamma", preset.input_gamma);
|
||||
parseFloatField(p, "output_gamma", preset.output_gamma);
|
||||
parseFloatField(p, "mask_brightness", preset.mask_brightness);
|
||||
parseFloatField(p, "curvature_x", preset.curvature_x);
|
||||
parseFloatField(p, "curvature_y", preset.curvature_y);
|
||||
parseIntField(p, "mask_type", preset.mask_type);
|
||||
parseBoolField(p, "enable_scanlines", preset.enable_scanlines);
|
||||
parseBoolField(p, "enable_multisample", preset.enable_multisample);
|
||||
parseBoolField(p, "enable_gamma", preset.enable_gamma);
|
||||
parseBoolField(p, "enable_curvature", preset.enable_curvature);
|
||||
parseBoolField(p, "enable_sharper", preset.enable_sharper);
|
||||
parseField(p, "scanline_weight", preset.scanline_weight);
|
||||
parseField(p, "scanline_gap_brightness", preset.scanline_gap_brightness);
|
||||
parseField(p, "bloom_factor", preset.bloom_factor);
|
||||
parseField(p, "input_gamma", preset.input_gamma);
|
||||
parseField(p, "output_gamma", preset.output_gamma);
|
||||
parseField(p, "mask_brightness", preset.mask_brightness);
|
||||
parseField(p, "curvature_x", preset.curvature_x);
|
||||
parseField(p, "curvature_y", preset.curvature_y);
|
||||
parseField(p, "mask_type", preset.mask_type);
|
||||
parseField(p, "enable_scanlines", preset.enable_scanlines);
|
||||
parseField(p, "enable_multisample", preset.enable_multisample);
|
||||
parseField(p, "enable_gamma", preset.enable_gamma);
|
||||
parseField(p, "enable_curvature", preset.enable_curvature);
|
||||
parseField(p, "enable_sharper", preset.enable_sharper);
|
||||
crtpi_presets.push_back(preset);
|
||||
}
|
||||
}
|
||||
@@ -353,98 +341,46 @@ namespace Options {
|
||||
void loadWindowFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("window")) { return; }
|
||||
const auto& win = yaml["window"];
|
||||
if (win.contains("zoom")) {
|
||||
try {
|
||||
int val = win["zoom"].get_value<int>();
|
||||
window.zoom = (val > 0) ? val : window.zoom;
|
||||
} catch (...) {}
|
||||
}
|
||||
int zoom = window.zoom;
|
||||
parseField(win, "zoom", zoom);
|
||||
window.zoom = (zoom > 0) ? zoom : window.zoom;
|
||||
}
|
||||
|
||||
void loadVideoFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("video")) { return; }
|
||||
const auto& vid = yaml["video"];
|
||||
|
||||
if (vid.contains("fullscreen")) {
|
||||
try {
|
||||
video.fullscreen = vid["fullscreen"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (vid.contains("scale_mode")) {
|
||||
try {
|
||||
video.scale_mode = static_cast<SDL_ScaleMode>(vid["scale_mode"].get_value<int>());
|
||||
} catch (...) {}
|
||||
}
|
||||
if (vid.contains("vsync")) {
|
||||
try {
|
||||
video.vsync = vid["vsync"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (vid.contains("integer_scale")) {
|
||||
try {
|
||||
video.integer_scale = vid["integer_scale"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(vid, "fullscreen", video.fullscreen);
|
||||
parseField(vid, "vsync", video.vsync);
|
||||
parseField(vid, "integer_scale", video.integer_scale);
|
||||
|
||||
int scale_mode_int = static_cast<int>(video.scale_mode);
|
||||
parseField(vid, "scale_mode", scale_mode_int);
|
||||
video.scale_mode = static_cast<SDL_ScaleMode>(scale_mode_int);
|
||||
|
||||
// --- GPU ---
|
||||
if (vid.contains("gpu")) {
|
||||
const auto& gpu_node = vid["gpu"];
|
||||
if (gpu_node.contains("acceleration")) {
|
||||
try {
|
||||
video.gpu.acceleration = gpu_node["acceleration"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (gpu_node.contains("preferred_driver")) {
|
||||
try {
|
||||
video.gpu.preferred_driver = gpu_node["preferred_driver"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(gpu_node, "acceleration", video.gpu.acceleration);
|
||||
parseField(gpu_node, "preferred_driver", video.gpu.preferred_driver);
|
||||
}
|
||||
|
||||
// --- Shader config ---
|
||||
if (vid.contains("shader")) {
|
||||
const auto& sh = vid["shader"];
|
||||
if (sh.contains("enabled")) {
|
||||
try {
|
||||
video.shader.enabled = sh["enabled"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (sh.contains("current_shader")) {
|
||||
try {
|
||||
auto s = sh["current_shader"].get_value<std::string>();
|
||||
video.shader.current_shader = (s == "crtpi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||
} catch (...) {}
|
||||
}
|
||||
if (sh.contains("postfx_preset")) {
|
||||
try {
|
||||
video.shader.current_postfx_preset_name = sh["postfx_preset"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (sh.contains("crtpi_preset")) {
|
||||
try {
|
||||
video.shader.current_crtpi_preset_name = sh["crtpi_preset"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
parseField(sh, "enabled", video.shader.enabled);
|
||||
parseField(sh, "postfx_preset", video.shader.current_postfx_preset_name);
|
||||
parseField(sh, "crtpi_preset", video.shader.current_crtpi_preset_name);
|
||||
std::string shader_name;
|
||||
parseField(sh, "current_shader", shader_name);
|
||||
if (!shader_name.empty()) {
|
||||
video.shader.current_shader = (shader_name == "crtpi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Supersampling ---
|
||||
if (vid.contains("supersampling")) {
|
||||
const auto& ss_node = vid["supersampling"];
|
||||
if (ss_node.contains("enabled")) {
|
||||
try {
|
||||
video.supersampling.enabled = ss_node["enabled"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (ss_node.contains("linear_upscale")) {
|
||||
try {
|
||||
video.supersampling.linear_upscale = ss_node["linear_upscale"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (ss_node.contains("downscale_algo")) {
|
||||
try {
|
||||
video.supersampling.downscale_algo = ss_node["downscale_algo"].get_value<int>();
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(ss_node, "enabled", video.supersampling.enabled);
|
||||
parseField(ss_node, "linear_upscale", video.supersampling.linear_upscale);
|
||||
parseField(ss_node, "downscale_algo", video.supersampling.downscale_algo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,50 +388,30 @@ namespace Options {
|
||||
if (!yaml.contains("audio")) { return; }
|
||||
const auto& aud = yaml["audio"];
|
||||
|
||||
if (aud.contains("enabled")) {
|
||||
try {
|
||||
audio.enabled = aud["enabled"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (aud.contains("volume")) {
|
||||
try {
|
||||
audio.volume = std::clamp(aud["volume"].get_value<float>(), 0.0F, 1.0F);
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(aud, "enabled", audio.enabled);
|
||||
parseField(aud, "volume", audio.volume);
|
||||
audio.volume = std::clamp(audio.volume, 0.0F, 1.0F);
|
||||
|
||||
if (aud.contains("music")) {
|
||||
const auto& mus = aud["music"];
|
||||
if (mus.contains("enabled")) {
|
||||
try {
|
||||
audio.music.enabled = mus["enabled"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (mus.contains("volume")) {
|
||||
try {
|
||||
audio.music.volume = std::clamp(mus["volume"].get_value<float>(), 0.0F, 1.0F);
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(mus, "enabled", audio.music.enabled);
|
||||
parseField(mus, "volume", audio.music.volume);
|
||||
audio.music.volume = std::clamp(audio.music.volume, 0.0F, 1.0F);
|
||||
}
|
||||
if (aud.contains("sound")) {
|
||||
const auto& snd = aud["sound"];
|
||||
if (snd.contains("enabled")) {
|
||||
try {
|
||||
audio.sound.enabled = snd["enabled"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (snd.contains("volume")) {
|
||||
try {
|
||||
audio.sound.volume = std::clamp(snd["volume"].get_value<float>(), 0.0F, 1.0F);
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(snd, "enabled", audio.sound.enabled);
|
||||
parseField(snd, "volume", audio.sound.volume);
|
||||
audio.sound.volume = std::clamp(audio.sound.volume, 0.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
void loadLoadingFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("loading")) { return; }
|
||||
const auto& ld = yaml["loading"];
|
||||
parseBoolField(ld, "show", loading.show);
|
||||
parseBoolField(ld, "show_resource_name", loading.show_resource_name);
|
||||
parseBoolField(ld, "wait_for_input", loading.wait_for_input);
|
||||
parseField(ld, "show", loading.show);
|
||||
parseField(ld, "show_resource_name", loading.show_resource_name);
|
||||
parseField(ld, "wait_for_input", loading.wait_for_input);
|
||||
}
|
||||
|
||||
void loadGameFromYaml(const fkyaml::node& yaml) {
|
||||
@@ -503,37 +419,23 @@ namespace Options {
|
||||
const auto& game = yaml["game"];
|
||||
|
||||
if (game.contains("language")) {
|
||||
try {
|
||||
auto lang = static_cast<Lang::Code>(game["language"].get_value<int>());
|
||||
if (lang == Lang::Code::ENGLISH || lang == Lang::Code::VALENCIAN || lang == Lang::Code::SPANISH) {
|
||||
settings.language = lang;
|
||||
} else {
|
||||
settings.language = Lang::Code::ENGLISH;
|
||||
}
|
||||
pending_changes.new_language = settings.language;
|
||||
} catch (...) {}
|
||||
int lang_int = static_cast<int>(settings.language);
|
||||
parseField(game, "language", lang_int);
|
||||
const auto LANG = static_cast<Lang::Code>(lang_int);
|
||||
settings.language = (LANG == Lang::Code::ENGLISH || LANG == Lang::Code::VALENCIAN || LANG == Lang::Code::SPANISH)
|
||||
? LANG
|
||||
: Lang::Code::ENGLISH;
|
||||
pending_changes.new_language = settings.language;
|
||||
}
|
||||
if (game.contains("difficulty")) {
|
||||
try {
|
||||
settings.difficulty = static_cast<Difficulty::Code>(game["difficulty"].get_value<int>());
|
||||
pending_changes.new_difficulty = settings.difficulty;
|
||||
} catch (...) {}
|
||||
}
|
||||
if (game.contains("autofire")) {
|
||||
try {
|
||||
settings.autofire = game["autofire"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (game.contains("shutdown_enabled")) {
|
||||
try {
|
||||
settings.shutdown_enabled = game["shutdown_enabled"].get_value<bool>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (game.contains("params_file")) {
|
||||
try {
|
||||
settings.params_file = game["params_file"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
int diff_int = static_cast<int>(settings.difficulty);
|
||||
parseField(game, "difficulty", diff_int);
|
||||
settings.difficulty = static_cast<Difficulty::Code>(diff_int);
|
||||
pending_changes.new_difficulty = settings.difficulty;
|
||||
}
|
||||
parseField(game, "autofire", settings.autofire);
|
||||
parseField(game, "shutdown_enabled", settings.shutdown_enabled);
|
||||
parseField(game, "params_file", settings.params_file);
|
||||
}
|
||||
|
||||
void loadControllersFromYaml(const fkyaml::node& yaml) {
|
||||
@@ -543,25 +445,14 @@ namespace Options {
|
||||
size_t i = 0;
|
||||
for (const auto& ctrl : controllers) {
|
||||
if (i >= GamepadManager::size()) { break; }
|
||||
if (ctrl.contains("name")) {
|
||||
try {
|
||||
gamepad_manager[i].name = ctrl["name"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (ctrl.contains("path")) {
|
||||
try {
|
||||
gamepad_manager[i].path = ctrl["path"].get_value<std::string>();
|
||||
} catch (...) {}
|
||||
}
|
||||
if (ctrl.contains("player")) {
|
||||
try {
|
||||
int player_int = ctrl["player"].get_value<int>();
|
||||
if (player_int == 1) {
|
||||
gamepad_manager[i].player_id = Player::Id::PLAYER1;
|
||||
} else if (player_int == 2) {
|
||||
gamepad_manager[i].player_id = Player::Id::PLAYER2;
|
||||
}
|
||||
} catch (...) {}
|
||||
parseField(ctrl, "name", gamepad_manager[i].name);
|
||||
parseField(ctrl, "path", gamepad_manager[i].path);
|
||||
int player_int = 0;
|
||||
parseField(ctrl, "player", player_int);
|
||||
if (player_int == 1) {
|
||||
gamepad_manager[i].player_id = Player::Id::PLAYER1;
|
||||
} else if (player_int == 2) {
|
||||
gamepad_manager[i].player_id = Player::Id::PLAYER2;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@@ -570,11 +461,9 @@ namespace Options {
|
||||
void loadKeyboardFromYaml(const fkyaml::node& yaml) {
|
||||
if (!yaml.contains("keyboard")) { return; }
|
||||
const auto& kb = yaml["keyboard"];
|
||||
if (kb.contains("player")) {
|
||||
try {
|
||||
keyboard.player_id = static_cast<Player::Id>(kb["player"].get_value<int>());
|
||||
} catch (...) {}
|
||||
}
|
||||
int player_int = static_cast<int>(keyboard.player_id);
|
||||
parseField(kb, "player", player_int);
|
||||
keyboard.player_id = static_cast<Player::Id>(player_int);
|
||||
}
|
||||
|
||||
// Carga el fichero de configuración
|
||||
@@ -595,11 +484,7 @@ namespace Options {
|
||||
|
||||
// Comprobar versión: si no coincide, regenerar config por defecto
|
||||
int file_version = 0;
|
||||
if (yaml.contains("version")) {
|
||||
try {
|
||||
file_version = yaml["version"].get_value<int>();
|
||||
} catch (...) {}
|
||||
}
|
||||
parseField(yaml, "version", file_version);
|
||||
if (file_version != Settings::CURRENT_CONFIG_VERSION) {
|
||||
std::cout << "Config version " << file_version << " != expected " << Settings::CURRENT_CONFIG_VERSION << ". Recreating defaults." << '\n';
|
||||
init();
|
||||
@@ -820,14 +705,14 @@ namespace Options {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto it = std::ranges::find_if(physical_gamepads,
|
||||
[this, &desired_path, &assigned_instances](const auto& pg) {
|
||||
const auto IT = std::ranges::find_if(physical_gamepads,
|
||||
[&desired_path, &assigned_instances](const auto& pg) {
|
||||
return pg->path == desired_path && !isGamepadAssigned(pg, assigned_instances);
|
||||
});
|
||||
if (it != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *it;
|
||||
gamepads_[i].name = (*it)->name;
|
||||
assigned_instances.push_back(*it);
|
||||
if (IT != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *IT;
|
||||
gamepads_[i].name = (*IT)->name;
|
||||
assigned_instances.push_back(*IT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -849,15 +734,15 @@ namespace Options {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto it = std::ranges::find_if(physical_gamepads,
|
||||
[this, &desired_name, &assigned_instances](const auto& pg) {
|
||||
const auto IT = std::ranges::find_if(physical_gamepads,
|
||||
[&desired_name, &assigned_instances](const auto& pg) {
|
||||
return pg->name == desired_name && !isGamepadAssigned(pg, assigned_instances);
|
||||
});
|
||||
if (it != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *it;
|
||||
gamepads_[i].name = (*it)->name;
|
||||
gamepads_[i].path = (*it)->path;
|
||||
assigned_instances.push_back(*it);
|
||||
if (IT != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *IT;
|
||||
gamepads_[i].name = (*IT)->name;
|
||||
gamepads_[i].path = (*IT)->path;
|
||||
assigned_instances.push_back(*IT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -871,15 +756,15 @@ namespace Options {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto it = std::ranges::find_if(physical_gamepads,
|
||||
[this, &assigned_instances](const auto& pg) {
|
||||
const auto IT = std::ranges::find_if(physical_gamepads,
|
||||
[&assigned_instances](const auto& pg) {
|
||||
return !isGamepadAssigned(pg, assigned_instances);
|
||||
});
|
||||
if (it != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *it;
|
||||
gamepads_[i].name = (*it)->name;
|
||||
gamepads_[i].path = (*it)->path;
|
||||
assigned_instances.push_back(*it);
|
||||
if (IT != physical_gamepads.end()) {
|
||||
gamepads_[i].instance = *IT;
|
||||
gamepads_[i].name = (*IT)->name;
|
||||
gamepads_[i].path = (*IT)->path;
|
||||
assigned_instances.push_back(*IT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,7 +726,7 @@ void Credits::drawBorderRect() {
|
||||
return; // no dibujar
|
||||
}
|
||||
|
||||
const Color COLOR = color_.LIGHTEN();
|
||||
const Color COLOR = color_.lighten();
|
||||
SDL_Renderer* rdr = Screen::get()->getRenderer();
|
||||
SDL_SetRenderDrawColor(rdr, COLOR.r, COLOR.g, COLOR.b, 0xFF);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/global_inputs.hpp" // Para check
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/input/input_types.hpp" // Para InputAction
|
||||
#include "core/input/pause_manager.hpp" // Para PauseManager
|
||||
#include "core/locale/lang.hpp" // Para getText
|
||||
#include "core/rendering/background.hpp" // Para Background
|
||||
@@ -341,7 +340,7 @@ void Game::updateStage() {
|
||||
|
||||
// Modificar color de fondo en la última fase
|
||||
if (current_stage_index == total_stages - 1) { // Última fase
|
||||
background_->setColor(Color(0xdd, 0x19, 0x1d).DARKEN());
|
||||
background_->setColor(Color(0xdd, 0x19, 0x1d).darken());
|
||||
background_->setAlpha(96);
|
||||
}
|
||||
}
|
||||
@@ -2183,10 +2182,10 @@ void Game::handleDebugEvents(const SDL_Event& event) {
|
||||
break;
|
||||
}
|
||||
case SDLK_8: {
|
||||
const auto it = std::ranges::find_if(players_,
|
||||
const auto IT = std::ranges::find_if(players_,
|
||||
[](const auto& player) { return player->isPlaying(); });
|
||||
if (it != players_.end()) {
|
||||
createItem(ItemType::COFFEE_MACHINE, (*it)->getPosX(), param.game.game_area.rect.y - Item::COFFEE_MACHINE_HEIGHT);
|
||||
if (IT != players_.end()) {
|
||||
createItem(ItemType::COFFEE_MACHINE, (*IT)->getPosX(), param.game.game_area.rect.y - Item::COFFEE_MACHINE_HEIGHT);
|
||||
coffee_machine_enabled_ = true;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64
|
||||
|
||||
#include <list> // Para list
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <list> // Para list
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/system/demo.hpp" // for Demo
|
||||
#include "game/entities/bullet.hpp" // for Bullet
|
||||
@@ -31,7 +32,7 @@ class Texture;
|
||||
struct Path;
|
||||
|
||||
namespace Difficulty {
|
||||
enum class Code;
|
||||
enum class Code : std::uint8_t;
|
||||
} // namespace Difficulty
|
||||
|
||||
// --- Clase Game: núcleo principal del gameplay ---
|
||||
@@ -71,7 +72,7 @@ class Game {
|
||||
using Players = std::vector<std::shared_ptr<Player>>;
|
||||
|
||||
// --- Enums ---
|
||||
enum class State {
|
||||
enum class State : std::uint8_t {
|
||||
FADE_IN, // Transición de entrada
|
||||
ENTERING_PLAYER, // Jugador entrando
|
||||
SHOWING_GET_READY_MESSAGE, // Mostrando mensaje de preparado
|
||||
|
||||
@@ -178,22 +178,17 @@ void HiScoreTable::updateFade(float delta_time) {
|
||||
|
||||
// Convierte un entero a un string con separadores de miles
|
||||
auto HiScoreTable::format(int number) -> std::string {
|
||||
const std::string SEPARATOR = ".";
|
||||
const std::string SCORE = std::to_string(number);
|
||||
const size_t SIZE = SCORE.size();
|
||||
|
||||
auto index = static_cast<int>(SCORE.size()) - 1;
|
||||
std::string result;
|
||||
auto i = 0;
|
||||
while (index >= 0) {
|
||||
result = SCORE.at(index) + result;
|
||||
index--;
|
||||
i++;
|
||||
if (i == 3) {
|
||||
i = 0;
|
||||
result = SEPARATOR + result;
|
||||
result.reserve(SIZE + (SIZE / 3));
|
||||
for (size_t i = 0; i < SIZE; ++i) {
|
||||
if (i > 0 && (SIZE - i) % 3 == 0) {
|
||||
result += '.';
|
||||
}
|
||||
result += SCORE[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -215,7 +210,7 @@ void HiScoreTable::createSprites() {
|
||||
const int FIRST_LINE = (param.game.height - SIZE) / 2;
|
||||
|
||||
// Crea el sprite para el texto de cabecera
|
||||
header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(Text::COLOR, Lang::getText("[HIGHSCORE_TABLE] CAPTION"), -2, background_fade_color_.INVERSE().LIGHTEN(25)));
|
||||
header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(Text::COLOR, Lang::getText("[HIGHSCORE_TABLE] CAPTION"), -2, background_fade_color_.inverse().lighten(25)));
|
||||
header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), FIRST_LINE);
|
||||
|
||||
// Crea los sprites para las entradas en la tabla de puntuaciones
|
||||
@@ -228,13 +223,14 @@ void HiScoreTable::createSprites() {
|
||||
const auto SCORE = format(Options::settings.hi_score_table.at(i).score);
|
||||
const auto NUM_DOTS = ENTRY_LENGTH - Options::settings.hi_score_table.at(i).name.size() - SCORE.size();
|
||||
const auto* const ONE_CC = Options::settings.hi_score_table.at(i).one_credit_complete ? " }" : "";
|
||||
std::string dots;
|
||||
for (int j = 0; std::cmp_less(j, NUM_DOTS); ++j) {
|
||||
dots = dots + ".";
|
||||
}
|
||||
const auto LINE = TABLE_POSITION + Options::settings.hi_score_table.at(i).name + dots + SCORE + ONE_CC;
|
||||
const std::string DOTS(NUM_DOTS, '.');
|
||||
std::string line = TABLE_POSITION;
|
||||
line += Options::settings.hi_score_table.at(i).name;
|
||||
line += DOTS;
|
||||
line += SCORE;
|
||||
line += ONE_CC;
|
||||
|
||||
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(Text::SHADOW, LINE, 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT)));
|
||||
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(Text::SHADOW, line, 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT)));
|
||||
const int DEFAULT_POS_X = (backbuffer_width - ENTRY_WIDTH) / 2;
|
||||
const int POS_X = (i < 9) ? DEFAULT_POS_X : DEFAULT_POS_X - entry_text->getCharacterSize();
|
||||
const int POS_Y = (i * SPACE_BETWEEN_LINES) + FIRST_LINE + SPACE_BETWEEN_HEADER;
|
||||
@@ -367,10 +363,10 @@ auto HiScoreTable::getEntryColor(int counter) -> Color {
|
||||
// Inicializa los colores de las entradas
|
||||
void HiScoreTable::iniEntryColors() {
|
||||
entry_colors_.clear();
|
||||
entry_colors_.emplace_back(background_fade_color_.INVERSE().LIGHTEN(75));
|
||||
entry_colors_.emplace_back(background_fade_color_.INVERSE().LIGHTEN(50));
|
||||
entry_colors_.emplace_back(background_fade_color_.INVERSE().LIGHTEN(25));
|
||||
entry_colors_.emplace_back(background_fade_color_.INVERSE());
|
||||
entry_colors_.emplace_back(background_fade_color_.inverse().lighten(75));
|
||||
entry_colors_.emplace_back(background_fade_color_.inverse().lighten(50));
|
||||
entry_colors_.emplace_back(background_fade_color_.inverse().lighten(25));
|
||||
entry_colors_.emplace_back(background_fade_color_.inverse());
|
||||
}
|
||||
|
||||
// Hace brillar los nombres de la tabla de records
|
||||
@@ -387,7 +383,7 @@ void HiScoreTable::glowEntryNames() {
|
||||
// Gestiona el contador
|
||||
void HiScoreTable::updateCounter() {
|
||||
if (elapsed_time_ >= BACKGROUND_CHANGE_S && !hiscore_flags_.background_changed) {
|
||||
background_->setColor(background_fade_color_.DARKEN());
|
||||
background_->setColor(background_fade_color_.darken());
|
||||
background_->setAlpha(96);
|
||||
hiscore_flags_.background_changed = true;
|
||||
}
|
||||
|
||||
@@ -392,17 +392,17 @@ void Intro::initSprites() {
|
||||
|
||||
const CardConfig CARD_CONFIGS[] = {
|
||||
// 0: Entra desde la izquierda. La 1 entra desde la derecha → sale empujada hacia la izquierda
|
||||
{-CARD_WIDTH, Y_DEST - 20.0F, CARD_ANGLE_0, -S, S * 0.1F, -A, 0.0F, -R},
|
||||
{.entry_x = -CARD_WIDTH, .entry_y = Y_DEST - 20.0F, .entry_angle = CARD_ANGLE_0, .exit_vx = -S, .exit_vy = S * 0.1F, .exit_ax = -A, .exit_ay = 0.0F, .exit_rotation = -R},
|
||||
// 1: Entra desde la derecha. La 2 entra desde arriba → sale empujada hacia abajo
|
||||
{W + CARD_WIDTH, Y_DEST + 15.0F, CARD_ANGLE_1, S * 0.15F, S, 0.0F, A, R * 1.1},
|
||||
{.entry_x = W + CARD_WIDTH, .entry_y = Y_DEST + 15.0F, .entry_angle = CARD_ANGLE_1, .exit_vx = S * 0.15F, .exit_vy = S, .exit_ax = 0.0F, .exit_ay = A, .exit_rotation = R * 1.1},
|
||||
// 2: Entra desde arriba. La 3 entra desde abajo → sale empujada hacia arriba
|
||||
{X_DEST + 30.0F, -CARD_HEIGHT, CARD_ANGLE_2, -S * 0.15F, -S, 0.0F, -A, -R * 0.9},
|
||||
{.entry_x = X_DEST + 30.0F, .entry_y = -CARD_HEIGHT, .entry_angle = CARD_ANGLE_2, .exit_vx = -S * 0.15F, .exit_vy = -S, .exit_ax = 0.0F, .exit_ay = -A, .exit_rotation = -R * 0.9},
|
||||
// 3: Entra desde abajo. La 4 entra desde arriba-izquierda → sale empujada hacia abajo-derecha
|
||||
{X_DEST - 25.0F, H + CARD_HEIGHT, CARD_ANGLE_3, S * 0.8F, S * 0.6F, A * 0.5F, A * 0.4F, R},
|
||||
{.entry_x = X_DEST - 25.0F, .entry_y = H + CARD_HEIGHT, .entry_angle = CARD_ANGLE_3, .exit_vx = S * 0.8F, .exit_vy = S * 0.6F, .exit_ax = A * 0.5F, .exit_ay = A * 0.4F, .exit_rotation = R},
|
||||
// 4: Entra desde arriba-izquierda. La 5 entra desde derecha-abajo → sale empujada hacia arriba-izquierda
|
||||
{-CARD_WIDTH * 0.5F, -CARD_HEIGHT, CARD_ANGLE_4, -S * 0.7F, -S * 0.5F, -A * 0.5F, -A * 0.3F, -R * 1.2},
|
||||
{.entry_x = -CARD_WIDTH * 0.5F, .entry_y = -CARD_HEIGHT, .entry_angle = CARD_ANGLE_4, .exit_vx = -S * 0.7F, .exit_vy = -S * 0.5F, .exit_ax = -A * 0.5F, .exit_ay = -A * 0.3F, .exit_rotation = -R * 1.2},
|
||||
// 5: Entra desde la derecha-abajo. Última: sale hacia la izquierda suave (viento)
|
||||
{W + CARD_WIDTH, H * 0.6F, CARD_ANGLE_5, -S * 0.6F, -S * 0.1F, -A * 0.5F, 0.0F, -R * 0.7},
|
||||
{.entry_x = W + CARD_WIDTH, .entry_y = H * 0.6F, .entry_angle = CARD_ANGLE_5, .exit_vx = -S * 0.6F, .exit_vy = -S * 0.1F, .exit_ax = -A * 0.5F, .exit_ay = 0.0F, .exit_rotation = -R * 0.7},
|
||||
};
|
||||
|
||||
// Inicializa los CardSprites
|
||||
@@ -534,15 +534,15 @@ void Intro::updatePostState() {
|
||||
if (ELAPSED_TIME >= POST_BG_STOP_DELAY_S) {
|
||||
tiled_bg_->stopGracefully();
|
||||
|
||||
if (!bg_color_.IS_EQUAL_TO(param.title.bg_color)) {
|
||||
bg_color_ = bg_color_.APPROACH_TO(param.title.bg_color, 1);
|
||||
if (!bg_color_.isEqualTo(param.title.bg_color)) {
|
||||
bg_color_ = bg_color_.approachTo(param.title.bg_color, 1);
|
||||
}
|
||||
|
||||
tiled_bg_->setColor(bg_color_);
|
||||
}
|
||||
|
||||
// Cambia de estado si el fondo se ha detenido y recuperado el color
|
||||
if (tiled_bg_->isStopped() && bg_color_.IS_EQUAL_TO(param.title.bg_color)) {
|
||||
if (tiled_bg_->isStopped() && bg_color_.isEqualTo(param.title.bg_color)) {
|
||||
post_state_ = PostState::END;
|
||||
state_start_time_ = SDL_GetTicks() / 1000.0F;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para Uint32, Uint64
|
||||
|
||||
#include <memory> // Para unique_ptr
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para unique_ptr
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/rendering/sprite/card_sprite.hpp" // Para CardSprite
|
||||
#include "core/rendering/tiled_bg.hpp" // Para TiledBG
|
||||
@@ -79,12 +80,12 @@ class Intro {
|
||||
static constexpr double CARD_ANGLE_5 = -7.0;
|
||||
|
||||
// --- Estados internos ---
|
||||
enum class State {
|
||||
enum class State : std::uint8_t {
|
||||
SCENES,
|
||||
POST,
|
||||
};
|
||||
|
||||
enum class PostState {
|
||||
enum class PostState : std::uint8_t {
|
||||
STOP_BG,
|
||||
END,
|
||||
};
|
||||
|
||||
@@ -14,6 +14,6 @@ class Preload {
|
||||
~Preload() = default;
|
||||
|
||||
// --- Callbacks para el bucle SDL_MAIN_USE_CALLBACKS ---
|
||||
void iterate(); // Repinta la barra de progreso
|
||||
void handleEvent(const SDL_Event& event); // Detecta pulsación en modo wait_for_input
|
||||
static void iterate(); // Repinta la barra de progreso
|
||||
static void handleEvent(const SDL_Event& event); // Detecta pulsación en modo wait_for_input
|
||||
};
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_Event, SDL_Keycode, SDL_PollEvent, SDLK_A, SDLK_C, SDLK_D, SDLK_F, SDLK_S, SDLK_V, SDLK_X, SDLK_Z, SDL_EventType, Uint64
|
||||
|
||||
#include <ranges> // Para __find_if_fn, find_if
|
||||
#include <string> // Para basic_string, char_traits, operator+, to_string, string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/global_inputs.hpp" // Para check
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/input/input_types.hpp" // Para InputAction
|
||||
#include "core/locale/lang.hpp" // Para getText
|
||||
#include "core/rendering/fade.hpp" // Para Fade
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
@@ -300,6 +298,9 @@ void Title::updateFade() {
|
||||
Section::options = Section::Options::GAME_PLAY_BOTH;
|
||||
Audio::get()->stopMusic();
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // COMBO és un bitmask 2-bit (0..3); arribar ací és impossible.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_Keycode, SDL_Event, Uint64
|
||||
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string_view> // Para string_view
|
||||
#include <vector> // Para vector
|
||||
@@ -69,7 +70,7 @@ class Title {
|
||||
static constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false; // Permite saltar la animación del título
|
||||
|
||||
// --- Enums ---
|
||||
enum class State {
|
||||
enum class State : std::uint8_t {
|
||||
LOGO_ANIMATING, // El logo está animándose
|
||||
LOGO_FINISHED, // El logo ha terminado de animarse
|
||||
START_HAS_BEEN_PRESSED, // Se ha pulsado el botón de start
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // Para max, clamp
|
||||
#include <cmath> // Para std::lround
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <functional> // Para function
|
||||
#include <numeric> // Para accumulate
|
||||
#include <string> // Para allocator, string, basic_string, to_string, operator==, char_traits
|
||||
@@ -16,7 +18,7 @@
|
||||
class MenuOption {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Behavior {
|
||||
enum class Behavior : std::uint8_t {
|
||||
ADJUST, // Solo puede ajustar valor (como IntOption, BoolOption, ListOption)
|
||||
SELECT, // Solo puede ejecutar acción (como ActionOption, FolderOption)
|
||||
BOTH // Puede tanto ajustar como ejecutar acción (como ActionListOption)
|
||||
@@ -119,11 +121,11 @@ class VolumeOption : public MenuOption {
|
||||
|
||||
[[nodiscard]] auto getBehavior() const -> Behavior override { return Behavior::ADJUST; }
|
||||
[[nodiscard]] auto getValueAsString() const -> std::string override {
|
||||
int pct = static_cast<int>(*linked_variable_ * 100.0F + 0.5F);
|
||||
int pct = static_cast<int>(std::lround(*linked_variable_ * 100.0F));
|
||||
return std::to_string(pct);
|
||||
}
|
||||
void adjustValue(bool adjust_up) override {
|
||||
int current = static_cast<int>(*linked_variable_ * 100.0F + 0.5F);
|
||||
int current = static_cast<int>(std::lround(*linked_variable_ * 100.0F));
|
||||
int new_value = std::clamp(current + (adjust_up ? step_value_ : -step_value_), 0, 100);
|
||||
*linked_variable_ = static_cast<float>(new_value) / 100.0F;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ void MenuRenderer::render(const ServiceMenu* menu_state) {
|
||||
SDL_RenderFillRect(Screen::get()->getRenderer(), &rect_);
|
||||
|
||||
// Dibuja el borde
|
||||
const Color BORDER_COLOR = param.service_menu.title_color.DARKEN();
|
||||
const Color BORDER_COLOR = param.service_menu.title_color.darken();
|
||||
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), BORDER_COLOR.r, BORDER_COLOR.g, BORDER_COLOR.b, 255);
|
||||
SDL_RenderRect(Screen::get()->getRenderer(), &rect_);
|
||||
SDL_RenderRect(Screen::get()->getRenderer(), &border_rect_);
|
||||
@@ -111,7 +111,7 @@ void MenuRenderer::render(const ServiceMenu* menu_state) {
|
||||
// Dibuja las opciones
|
||||
y = options_y_;
|
||||
const auto& option_pairs = menu_state->getOptionPairs();
|
||||
const float ROW_HEIGHT = static_cast<float>(options_height_ + options_padding_);
|
||||
const auto ROW_HEIGHT = static_cast<float>(options_height_ + options_padding_);
|
||||
|
||||
for (size_t i = 0; i < option_pairs.size(); ++i) {
|
||||
const bool IS_SELECTED = (i == menu_state->getSelectedIndex());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -17,7 +18,7 @@ class Text;
|
||||
class MenuRenderer {
|
||||
public:
|
||||
// --- Nuevo: Enum para el modo de posicionamiento ---
|
||||
enum class PositionMode {
|
||||
enum class PositionMode : std::uint8_t {
|
||||
CENTERED, // La ventana se centra en el punto especificado
|
||||
FIXED // La esquina superior izquierda coincide con el punto
|
||||
};
|
||||
@@ -94,7 +95,7 @@ class MenuRenderer {
|
||||
} resize_animation_;
|
||||
|
||||
struct ShowHideAnimation {
|
||||
enum class Type { NONE,
|
||||
enum class Type : std::uint8_t { NONE,
|
||||
SHOWING,
|
||||
HIDING };
|
||||
Type type = Type::NONE;
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_Renderer
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para basic_string, string
|
||||
#include <vector> // Para vector
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para basic_string, string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "utils/color.hpp" // Para stringInVector, Color
|
||||
#include "utils/utils.hpp"
|
||||
@@ -17,7 +18,7 @@ class Texture;
|
||||
class Notifier {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Position {
|
||||
enum class Position : std::uint8_t {
|
||||
TOP, // Parte superior
|
||||
BOTTOM, // Parte inferior
|
||||
LEFT, // Lado izquierdo
|
||||
@@ -46,14 +47,14 @@ class Notifier {
|
||||
static constexpr float ANIMATION_SPEED_PX_PER_S = 60.0F; // Velocidad de animación (1 pixel/frame @ 60fps)
|
||||
|
||||
// --- Enums privados ---
|
||||
enum class State {
|
||||
enum class State : std::uint8_t {
|
||||
RISING, // Apareciendo
|
||||
STAY, // Visible
|
||||
VANISHING, // Desapareciendo
|
||||
FINISHED, // Terminada
|
||||
};
|
||||
|
||||
enum class Shape {
|
||||
enum class Shape : std::uint8_t {
|
||||
ROUNDED, // Forma redondeada
|
||||
SQUARED, // Forma cuadrada
|
||||
};
|
||||
|
||||
+115
-110
@@ -8,7 +8,6 @@
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/define_buttons.hpp" // Para DefineButtons
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/input/input_types.hpp" // Para InputAction
|
||||
#include "core/locale/lang.hpp" // Para getText, getCodeFromName, getNameFromCode
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/resources/resource.hpp" // Para Resource
|
||||
@@ -252,9 +251,9 @@ void ServiceMenu::applySettingsSettings() {
|
||||
}
|
||||
|
||||
auto ServiceMenu::getOptionByCaption(const std::string& caption) const -> MenuOption* {
|
||||
const auto it = std::ranges::find_if(options_,
|
||||
const auto IT = std::ranges::find_if(options_,
|
||||
[&caption](const auto& option) { return option->getCaption() == caption; });
|
||||
return it != options_.end() ? it->get() : nullptr;
|
||||
return IT != options_.end() ? IT->get() : nullptr;
|
||||
}
|
||||
|
||||
// --- Getters y otros ---
|
||||
@@ -279,8 +278,16 @@ auto ServiceMenu::countOptionsInGroup(SettingsGroup group) const -> size_t {
|
||||
// Inicializa todas las opciones del menú
|
||||
void ServiceMenu::initializeOptions() {
|
||||
options_.clear();
|
||||
addControlsOptions();
|
||||
addVideoOptions();
|
||||
addAudioOptions();
|
||||
addSettingsOptions();
|
||||
addSystemOptions();
|
||||
addMainMenuOptions();
|
||||
setHiddenOptions();
|
||||
}
|
||||
|
||||
// CONTROLS - Usando ActionListOption para mandos
|
||||
void ServiceMenu::addControlsOptions() {
|
||||
options_.push_back(std::make_unique<ActionListOption>(
|
||||
Lang::getText("[SERVICE_MENU] CONTROLLER1"),
|
||||
SettingsGroup::CONTROLS,
|
||||
@@ -292,7 +299,6 @@ void ServiceMenu::initializeOptions() {
|
||||
Options::gamepad_manager.assignGamepadToPlayer(Player::Id::PLAYER1, Input::get()->getGamepadByName(val), val);
|
||||
},
|
||||
[this]() -> void {
|
||||
// Acción: configurar botones del mando del jugador 1
|
||||
auto* gamepad = &Options::gamepad_manager.getGamepad(Player::Id::PLAYER1);
|
||||
if (gamepad->instance != nullptr) {
|
||||
define_buttons_->enable(gamepad);
|
||||
@@ -310,14 +316,12 @@ void ServiceMenu::initializeOptions() {
|
||||
Options::gamepad_manager.assignGamepadToPlayer(Player::Id::PLAYER2, Input::get()->getGamepadByName(val), val);
|
||||
},
|
||||
[this]() -> void {
|
||||
// Acción: configurar botones del mando del jugador 2
|
||||
auto* gamepad = &Options::gamepad_manager.getGamepad(Player::Id::PLAYER2);
|
||||
if (gamepad->instance != nullptr) {
|
||||
define_buttons_->enable(gamepad);
|
||||
}
|
||||
}));
|
||||
|
||||
// CONTROLS - Opción para teclado (solo lista, sin acción)
|
||||
options_.push_back(std::make_unique<ListOption>(
|
||||
Lang::getText("[SERVICE_MENU] KEYBOARD"),
|
||||
SettingsGroup::CONTROLS,
|
||||
@@ -325,26 +329,22 @@ void ServiceMenu::initializeOptions() {
|
||||
Lang::getText("[SERVICE_MENU] PLAYER1"),
|
||||
Lang::getText("[SERVICE_MENU] PLAYER2")},
|
||||
[]() -> std::string {
|
||||
// Devolver el jugador actual asignado al teclado
|
||||
return Options::playerIdToString(Options::getPlayerWhoUsesKeyboard());
|
||||
},
|
||||
[](const std::string& val) -> void {
|
||||
// Asignar el teclado al jugador seleccionado
|
||||
Options::keyboard.assignTo(Options::stringToPlayerId(val));
|
||||
}));
|
||||
|
||||
// CONTROLS - Acción para intercambiar mandos
|
||||
options_.push_back(std::make_unique<ActionOption>(
|
||||
Lang::getText("[SERVICE_MENU] SWAP_CONTROLLERS"),
|
||||
SettingsGroup::CONTROLS,
|
||||
[this]() -> void {
|
||||
Options::gamepad_manager.swapPlayers();
|
||||
adjustListValues(); // Sincroniza el valor de las opciones de lista (como MANDO1) con los datos reales
|
||||
updateOptionPairs(); // Actualiza los pares de texto <opción, valor> que se van a dibujar
|
||||
adjustListValues();
|
||||
updateOptionPairs();
|
||||
|
||||
// Feedback visual: anima el intercambio de los valores entre
|
||||
// las filas de MANDO 1 y MANDO 2, imprescindible cuando los dos
|
||||
// mandos tienen el mismo nombre (el texto no cambia al swap).
|
||||
// Feedback visual: anima el intercambio de las filas de MANDO 1 y MANDO 2,
|
||||
// imprescindible cuando ambos mandos tienen el mismo nombre (el texto no cambia).
|
||||
const std::string CAPTION1 = Lang::getText("[SERVICE_MENU] CONTROLLER1");
|
||||
const std::string CAPTION2 = Lang::getText("[SERVICE_MENU] CONTROLLER2");
|
||||
size_t idx1 = display_options_.size();
|
||||
@@ -358,8 +358,9 @@ void ServiceMenu::initializeOptions() {
|
||||
renderer_->startSwapAnimation(idx1, idx2);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// VIDEO
|
||||
void ServiceMenu::addVideoOptions() {
|
||||
options_.push_back(std::make_unique<BoolOption>(
|
||||
Lang::getText("[SERVICE_MENU] FULLSCREEN"),
|
||||
SettingsGroup::VIDEO,
|
||||
@@ -373,76 +374,8 @@ void ServiceMenu::initializeOptions() {
|
||||
Options::window.max_zoom,
|
||||
1));
|
||||
|
||||
// Shader: Desactivat / PostFX / CrtPi
|
||||
{
|
||||
std::string disabled_text = Lang::getText("[SERVICE_MENU] SHADER_DISABLED");
|
||||
std::vector<std::string> shader_values = {disabled_text, "PostFX", "CrtPi"};
|
||||
auto shader_getter = [disabled_text]() -> std::string {
|
||||
// NOLINTNEXTLINE(performance-no-automatic-move) -- captura por valor en lambda const, no se puede mover
|
||||
if (!Options::video.shader.enabled) { return disabled_text; }
|
||||
return (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) ? "CrtPi" : "PostFX";
|
||||
};
|
||||
auto shader_setter = [disabled_text](const std::string& val) {
|
||||
if (val == disabled_text) {
|
||||
Options::video.shader.enabled = false;
|
||||
} else {
|
||||
Options::video.shader.enabled = true;
|
||||
const auto TYPE = (val == "CrtPi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||
Options::video.shader.current_shader = TYPE;
|
||||
auto* screen = Screen::get();
|
||||
if (screen != nullptr) {
|
||||
screen->applySettings();
|
||||
}
|
||||
}
|
||||
Screen::initShaders();
|
||||
};
|
||||
options_.push_back(std::make_unique<ListOption>(
|
||||
Lang::getText("[SERVICE_MENU] SHADER"),
|
||||
SettingsGroup::VIDEO,
|
||||
shader_values,
|
||||
shader_getter,
|
||||
shader_setter));
|
||||
}
|
||||
|
||||
// Preset: muestra nombre, cicla circularmente entre presets del shader activo
|
||||
{
|
||||
auto preset_getter = []() -> std::string {
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
if (Options::crtpi_presets.empty()) { return ""; }
|
||||
return Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset)).name;
|
||||
}
|
||||
if (Options::postfx_presets.empty()) { return ""; }
|
||||
return Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset)).name;
|
||||
};
|
||||
auto preset_adjuster = [](bool up) {
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
if (Options::crtpi_presets.empty()) { return; }
|
||||
const int SIZE = static_cast<int>(Options::crtpi_presets.size());
|
||||
Options::video.shader.current_crtpi_preset = up
|
||||
? (Options::video.shader.current_crtpi_preset + 1) % SIZE
|
||||
: (Options::video.shader.current_crtpi_preset + SIZE - 1) % SIZE;
|
||||
} else {
|
||||
if (Options::postfx_presets.empty()) { return; }
|
||||
const int SIZE = static_cast<int>(Options::postfx_presets.size());
|
||||
Options::video.shader.current_postfx_preset = up
|
||||
? (Options::video.shader.current_postfx_preset + 1) % SIZE
|
||||
: (Options::video.shader.current_postfx_preset + SIZE - 1) % SIZE;
|
||||
}
|
||||
Screen::initShaders();
|
||||
};
|
||||
auto preset_max_width = [](const Text* text) -> int {
|
||||
const auto presets_length = [text](int max_w, const auto& p) { return std::max(max_w, text->length(p.name, -2)); };
|
||||
int max_w = std::accumulate(Options::postfx_presets.begin(), Options::postfx_presets.end(), 0, presets_length);
|
||||
return std::accumulate(Options::crtpi_presets.begin(), Options::crtpi_presets.end(), max_w, presets_length);
|
||||
};
|
||||
|
||||
options_.push_back(std::make_unique<CallbackOption>(
|
||||
Lang::getText("[SERVICE_MENU] SHADER_PRESET"),
|
||||
SettingsGroup::VIDEO,
|
||||
preset_getter,
|
||||
preset_adjuster,
|
||||
preset_max_width));
|
||||
}
|
||||
addVideoShaderOption();
|
||||
addVideoPresetOption();
|
||||
|
||||
options_.push_back(std::make_unique<BoolOption>(
|
||||
Lang::getText("[SERVICE_MENU] SUPERSAMPLING"),
|
||||
@@ -459,25 +392,97 @@ void ServiceMenu::initializeOptions() {
|
||||
SettingsGroup::VIDEO,
|
||||
&Options::video.integer_scale));
|
||||
|
||||
// FILTER: Nearest / Linear (solo visible en el fallback SDL, sin GPU acelerada)
|
||||
{
|
||||
std::vector<std::string> filter_values = {"Nearest", "Linear"};
|
||||
auto filter_getter = []() -> std::string {
|
||||
return (Options::video.scale_mode == SDL_SCALEMODE_LINEAR) ? "Linear" : "Nearest";
|
||||
};
|
||||
auto filter_setter = [](const std::string& val) {
|
||||
Options::video.scale_mode = (val == "Linear") ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST;
|
||||
if (Screen::get() != nullptr) { Screen::get()->applyFilter(); }
|
||||
};
|
||||
options_.push_back(std::make_unique<ListOption>(
|
||||
Lang::getText("[SERVICE_MENU] FILTER"),
|
||||
SettingsGroup::VIDEO,
|
||||
filter_values,
|
||||
filter_getter,
|
||||
filter_setter));
|
||||
}
|
||||
addVideoFilterOption();
|
||||
}
|
||||
|
||||
// AUDIO
|
||||
void ServiceMenu::addVideoShaderOption() {
|
||||
std::string disabled_text = Lang::getText("[SERVICE_MENU] SHADER_DISABLED");
|
||||
std::vector<std::string> shader_values = {disabled_text, "PostFX", "CrtPi"};
|
||||
auto shader_getter = [disabled_text]() -> std::string {
|
||||
// NOLINTNEXTLINE(performance-no-automatic-move) -- captura por valor en lambda const, no se puede mover
|
||||
if (!Options::video.shader.enabled) { return disabled_text; }
|
||||
return (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) ? "CrtPi" : "PostFX";
|
||||
};
|
||||
auto shader_setter = [disabled_text](const std::string& val) {
|
||||
if (val == disabled_text) {
|
||||
Options::video.shader.enabled = false;
|
||||
} else {
|
||||
Options::video.shader.enabled = true;
|
||||
const auto TYPE = (val == "CrtPi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||
Options::video.shader.current_shader = TYPE;
|
||||
auto* screen = Screen::get();
|
||||
if (screen != nullptr) {
|
||||
screen->applySettings();
|
||||
}
|
||||
}
|
||||
Screen::initShaders();
|
||||
};
|
||||
options_.push_back(std::make_unique<ListOption>(
|
||||
Lang::getText("[SERVICE_MENU] SHADER"),
|
||||
SettingsGroup::VIDEO,
|
||||
shader_values,
|
||||
shader_getter,
|
||||
shader_setter));
|
||||
}
|
||||
|
||||
void ServiceMenu::addVideoPresetOption() {
|
||||
auto preset_getter = []() -> std::string {
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
if (Options::crtpi_presets.empty()) { return ""; }
|
||||
return Options::crtpi_presets.at(static_cast<size_t>(Options::video.shader.current_crtpi_preset)).name;
|
||||
}
|
||||
if (Options::postfx_presets.empty()) { return ""; }
|
||||
return Options::postfx_presets.at(static_cast<size_t>(Options::video.shader.current_postfx_preset)).name;
|
||||
};
|
||||
auto preset_adjuster = [](bool up) {
|
||||
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||
if (Options::crtpi_presets.empty()) { return; }
|
||||
const int SIZE = static_cast<int>(Options::crtpi_presets.size());
|
||||
Options::video.shader.current_crtpi_preset = up
|
||||
? (Options::video.shader.current_crtpi_preset + 1) % SIZE
|
||||
: (Options::video.shader.current_crtpi_preset + SIZE - 1) % SIZE;
|
||||
} else {
|
||||
if (Options::postfx_presets.empty()) { return; }
|
||||
const int SIZE = static_cast<int>(Options::postfx_presets.size());
|
||||
Options::video.shader.current_postfx_preset = up
|
||||
? (Options::video.shader.current_postfx_preset + 1) % SIZE
|
||||
: (Options::video.shader.current_postfx_preset + SIZE - 1) % SIZE;
|
||||
}
|
||||
Screen::initShaders();
|
||||
};
|
||||
auto preset_max_width = [](const Text* text) -> int {
|
||||
const auto PRESETS_LENGTH = [text](int max_w, const auto& p) { return std::max(max_w, text->length(p.name, -2)); };
|
||||
int max_w = std::accumulate(Options::postfx_presets.begin(), Options::postfx_presets.end(), 0, PRESETS_LENGTH);
|
||||
return std::accumulate(Options::crtpi_presets.begin(), Options::crtpi_presets.end(), max_w, PRESETS_LENGTH);
|
||||
};
|
||||
|
||||
options_.push_back(std::make_unique<CallbackOption>(
|
||||
Lang::getText("[SERVICE_MENU] SHADER_PRESET"),
|
||||
SettingsGroup::VIDEO,
|
||||
preset_getter,
|
||||
preset_adjuster,
|
||||
preset_max_width));
|
||||
}
|
||||
|
||||
void ServiceMenu::addVideoFilterOption() {
|
||||
// FILTER: Nearest / Linear (solo visible en el fallback SDL, sin GPU acelerada)
|
||||
std::vector<std::string> filter_values = {"Nearest", "Linear"};
|
||||
auto filter_getter = []() -> std::string {
|
||||
return (Options::video.scale_mode == SDL_SCALEMODE_LINEAR) ? "Linear" : "Nearest";
|
||||
};
|
||||
auto filter_setter = [](const std::string& val) {
|
||||
Options::video.scale_mode = (val == "Linear") ? SDL_SCALEMODE_LINEAR : SDL_SCALEMODE_NEAREST;
|
||||
if (Screen::get() != nullptr) { Screen::get()->applyFilter(); }
|
||||
};
|
||||
options_.push_back(std::make_unique<ListOption>(
|
||||
Lang::getText("[SERVICE_MENU] FILTER"),
|
||||
SettingsGroup::VIDEO,
|
||||
filter_values,
|
||||
filter_getter,
|
||||
filter_setter));
|
||||
}
|
||||
|
||||
void ServiceMenu::addAudioOptions() {
|
||||
options_.push_back(std::make_unique<BoolOption>(
|
||||
Lang::getText("[SERVICE_MENU] AUDIO"),
|
||||
SettingsGroup::AUDIO,
|
||||
@@ -500,8 +505,9 @@ void ServiceMenu::initializeOptions() {
|
||||
SettingsGroup::AUDIO,
|
||||
&Options::audio.sound.volume,
|
||||
5));
|
||||
}
|
||||
|
||||
// SETTINGS
|
||||
void ServiceMenu::addSettingsOptions() {
|
||||
options_.push_back(std::make_unique<BoolOption>(
|
||||
Lang::getText("[SERVICE_MENU] AUTOFIRE"),
|
||||
SettingsGroup::SETTINGS,
|
||||
@@ -541,8 +547,9 @@ void ServiceMenu::initializeOptions() {
|
||||
Lang::getText("[SERVICE_MENU] ENABLE_SHUTDOWN"),
|
||||
SettingsGroup::SETTINGS,
|
||||
&Options::settings.shutdown_enabled));
|
||||
}
|
||||
|
||||
// SYSTEM
|
||||
void ServiceMenu::addSystemOptions() {
|
||||
options_.push_back(std::make_unique<ActionOption>(
|
||||
Lang::getText("[SERVICE_MENU] RESET"),
|
||||
SettingsGroup::SYSTEM,
|
||||
@@ -567,8 +574,9 @@ void ServiceMenu::initializeOptions() {
|
||||
Section::options = Section::Options::SHUTDOWN;
|
||||
},
|
||||
!Options::settings.shutdown_enabled));
|
||||
}
|
||||
|
||||
// MAIN MENU
|
||||
void ServiceMenu::addMainMenuOptions() {
|
||||
options_.push_back(std::make_unique<FolderOption>(
|
||||
Lang::getText("[SERVICE_MENU] CONTROLS"),
|
||||
SettingsGroup::MAIN,
|
||||
@@ -593,9 +601,6 @@ void ServiceMenu::initializeOptions() {
|
||||
Lang::getText("[SERVICE_MENU] SYSTEM"),
|
||||
SettingsGroup::MAIN,
|
||||
SettingsGroup::SYSTEM));
|
||||
|
||||
// Oculta opciones según configuración
|
||||
setHiddenOptions();
|
||||
}
|
||||
|
||||
// Sincroniza los valores de las opciones tipo lista
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <cstddef> // Para size_t
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <functional> // Para function
|
||||
#include <iterator> // Para pair
|
||||
#include <memory> // Para unique_ptr
|
||||
#include <string> // Para basic_string, string
|
||||
#include <utility> // Para pair
|
||||
@@ -104,6 +103,15 @@ class ServiceMenu {
|
||||
void updateDisplayOptions();
|
||||
void updateOptionPairs();
|
||||
void initializeOptions();
|
||||
void addControlsOptions(); // CONTROLS: mandos 1/2, teclat, swap
|
||||
void addVideoOptions(); // VIDEO: orquestra els blocs de vídeo
|
||||
void addVideoShaderOption(); // VIDEO: tria de shader (Disabled/PostFX/CrtPi)
|
||||
void addVideoPresetOption(); // VIDEO: cicla presets del shader actiu
|
||||
void addVideoFilterOption(); // VIDEO: filtre Nearest/Linear (fallback SDL)
|
||||
void addAudioOptions(); // AUDIO: enabled + tres volums
|
||||
void addSettingsOptions(); // SETTINGS: autofire, idioma, dificultat, shutdown
|
||||
void addSystemOptions(); // SYSTEM: reset, quit, shutdown
|
||||
void addMainMenuOptions(); // MAIN: carpetes de menú
|
||||
void updateMenu();
|
||||
void applySettings();
|
||||
void applyControlsSettings();
|
||||
|
||||
+3
-3
@@ -12,16 +12,16 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024
|
||||
|
||||
#include "core/system/director.hpp" // Para Director
|
||||
|
||||
SDL_AppResult SDL_AppInit(void** appstate, int /*argc*/, char** /*argv*/) {
|
||||
auto SDL_AppInit(void** appstate, int /*argc*/, char** /*argv*/) -> SDL_AppResult {
|
||||
*appstate = new Director();
|
||||
return SDL_APP_CONTINUE;
|
||||
}
|
||||
|
||||
SDL_AppResult SDL_AppIterate(void* appstate) {
|
||||
auto SDL_AppIterate(void* appstate) -> SDL_AppResult {
|
||||
return static_cast<Director*>(appstate)->iterate();
|
||||
}
|
||||
|
||||
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) {
|
||||
auto SDL_AppEvent(void* appstate, SDL_Event* event) -> SDL_AppResult {
|
||||
return static_cast<Director*>(appstate)->handleEvent(*event);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ auto Color::fromHex(const std::string& hex_str) -> Color {
|
||||
}
|
||||
|
||||
// Implementaciones de métodos estáticos de Color
|
||||
constexpr auto Color::RGB_TO_HSV(Color color) -> HSV {
|
||||
constexpr auto Color::rgbToHsv(Color color) -> HSV {
|
||||
float r = color.r / 255.0F;
|
||||
float g = color.g / 255.0F;
|
||||
float b = color.b / 255.0F;
|
||||
@@ -72,7 +72,7 @@ constexpr auto Color::RGB_TO_HSV(Color color) -> HSV {
|
||||
return {.h = h, .s = s, .v = v};
|
||||
}
|
||||
|
||||
constexpr auto Color::HSV_TO_RGB(HSV hsv) -> Color {
|
||||
constexpr auto Color::hsvToRgb(HSV hsv) -> Color {
|
||||
float c = hsv.v * hsv.s;
|
||||
float x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1));
|
||||
float m = hsv.v - c;
|
||||
@@ -132,7 +132,7 @@ namespace Colors {
|
||||
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
|
||||
Cycle result{};
|
||||
HSV base_hsv = Color::RGB_TO_HSV(base);
|
||||
HSV base_hsv = Color::rgbToHsv(base);
|
||||
|
||||
for (size_t i = 0; i < CYCLE_SIZE; ++i) {
|
||||
float t = static_cast<float>(i) / (CYCLE_SIZE - 1); // 0 → 1
|
||||
@@ -175,7 +175,7 @@ namespace Colors {
|
||||
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||
|
||||
Color c = Color::HSV_TO_RGB(adjusted);
|
||||
Color c = Color::hsvToRgb(adjusted);
|
||||
result[i] = c;
|
||||
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
|
||||
}
|
||||
|
||||
+13
-12
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <algorithm> // Para max, min
|
||||
#include <array> // Para array
|
||||
#include <cstdint> // Para std::uint8_t
|
||||
#include <cstdlib> // Para size_t, abs
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
@@ -48,11 +49,11 @@ struct Color {
|
||||
b(blue),
|
||||
a(alpha) {}
|
||||
|
||||
[[nodiscard]] constexpr auto INVERSE() const -> Color {
|
||||
[[nodiscard]] constexpr auto inverse() const -> Color {
|
||||
return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto LIGHTEN(int amount = DEFAULT_LIGHTEN_AMOUNT) const -> Color {
|
||||
[[nodiscard]] constexpr auto lighten(int amount = DEFAULT_LIGHTEN_AMOUNT) const -> Color {
|
||||
return Color(
|
||||
std::min(static_cast<int>(MAX_COLOR_VALUE), r + amount),
|
||||
std::min(static_cast<int>(MAX_COLOR_VALUE), g + amount),
|
||||
@@ -60,7 +61,7 @@ struct Color {
|
||||
a);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto DARKEN(int amount = DEFAULT_DARKEN_AMOUNT) const -> Color {
|
||||
[[nodiscard]] constexpr auto darken(int amount = DEFAULT_DARKEN_AMOUNT) const -> Color {
|
||||
return Color(
|
||||
std::max(static_cast<int>(MIN_COLOR_VALUE), r - amount),
|
||||
std::max(static_cast<int>(MIN_COLOR_VALUE), g - amount),
|
||||
@@ -72,14 +73,14 @@ struct Color {
|
||||
static auto fromHex(const std::string& hex_str) -> Color;
|
||||
|
||||
// Conversiones de formato de color
|
||||
[[nodiscard]] constexpr static auto RGB_TO_HSV(Color color) -> HSV;
|
||||
[[nodiscard]] constexpr static auto HSV_TO_RGB(HSV hsv) -> Color;
|
||||
[[nodiscard]] constexpr static auto rgbToHsv(Color color) -> HSV;
|
||||
[[nodiscard]] constexpr static auto hsvToRgb(HSV hsv) -> Color;
|
||||
|
||||
[[nodiscard]] constexpr auto IS_EQUAL_TO(const Color& other) const -> bool {
|
||||
[[nodiscard]] constexpr auto isEqualTo(const Color& other) const -> bool {
|
||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto APPROACH_TO(const Color& target, int step = DEFAULT_APPROACH_STEP) const -> Color {
|
||||
[[nodiscard]] constexpr auto approachTo(const Color& target, int step = DEFAULT_APPROACH_STEP) const -> Color {
|
||||
auto approach_component = [step](Uint8 current, Uint8 target_val) -> Uint8 {
|
||||
if (std::abs(current - target_val) <= step) {
|
||||
return target_val;
|
||||
@@ -96,7 +97,7 @@ struct Color {
|
||||
}
|
||||
|
||||
// Interpolación lineal hacia otro color (t=0.0: this, t=1.0: target)
|
||||
[[nodiscard]] constexpr auto LERP(const Color& target, float t) const -> Color {
|
||||
[[nodiscard]] constexpr auto lerp(const Color& target, float t) const -> Color {
|
||||
// Asegurar que t esté en el rango [0.0, 1.0]
|
||||
t = std::clamp(t, 0.0F, 1.0F);
|
||||
|
||||
@@ -113,12 +114,12 @@ struct Color {
|
||||
}
|
||||
|
||||
// Sobrecarga para aceptar componentes RGBA directamente
|
||||
[[nodiscard]] constexpr auto LERP(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha, float t) const -> Color {
|
||||
return LERP(Color(red, green, blue, alpha), t);
|
||||
[[nodiscard]] constexpr auto lerp(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha, float t) const -> Color {
|
||||
return lerp(Color(red, green, blue, alpha), t);
|
||||
}
|
||||
|
||||
// Convierte el color a un entero de 32 bits en formato RGBA
|
||||
[[nodiscard]] constexpr auto TO_UINT32() const -> Uint32 {
|
||||
[[nodiscard]] constexpr auto toUint32() const -> Uint32 {
|
||||
return (static_cast<Uint32>(r) << 24) |
|
||||
(static_cast<Uint32>(g) << 16) |
|
||||
(static_cast<Uint32>(b) << 8) |
|
||||
@@ -127,7 +128,7 @@ struct Color {
|
||||
};
|
||||
|
||||
// --- Enum ColorCycleStyle: define estilos de ciclo de color ---
|
||||
enum class ColorCycleStyle {
|
||||
enum class ColorCycleStyle : std::uint8_t {
|
||||
SUBTLE_PULSE, // Variación leve en brillo (por defecto)
|
||||
HUE_WAVE, // Variación suave en tono (sin verde)
|
||||
VIBRANT, // Cambios agresivos en tono y brillo
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para string, basic_string, stoi, stof, hash, allocator, operator==, char_traits, operator+, operator>>, getline
|
||||
#include <unordered_map> // Para unordered_map, operator==, _Node_iterator_base
|
||||
#include <utility> // Para pair
|
||||
|
||||
#include "game/ui/notifier.hpp" // Para Notifier
|
||||
#include "utils/color.hpp" // Para Color
|
||||
|
||||
+12
-12
@@ -167,51 +167,51 @@ struct ParamPlayer {
|
||||
};
|
||||
|
||||
// Inicialización con valores por defecto
|
||||
const Shirt default_player0_shirt = Shirt(
|
||||
const Shirt DEFAULT_PLAYER0_SHIRT = Shirt(
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER0_DARK),
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER0_BASE),
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER0_LIGHT));
|
||||
|
||||
const Shirt default_player1_shirt = Shirt(
|
||||
const Shirt DEFAULT_PLAYER1_SHIRT = Shirt(
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER1_DARK),
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER1_BASE),
|
||||
Color::fromHex(Defaults::Player::DefaultShirt::PLAYER1_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> default_shirt = {default_player0_shirt, default_player1_shirt};
|
||||
std::array<Shirt, 2> default_shirt = {DEFAULT_PLAYER0_SHIRT, DEFAULT_PLAYER1_SHIRT};
|
||||
|
||||
const Shirt one_coffee_player0_shirt = Shirt(
|
||||
const Shirt ONE_COFFEE_PLAYER0_SHIRT = Shirt(
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER0_DARK),
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER0_BASE),
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER0_LIGHT));
|
||||
|
||||
const Shirt one_coffee_player1_shirt = Shirt(
|
||||
const Shirt ONE_COFFEE_PLAYER1_SHIRT = Shirt(
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER1_DARK),
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER1_BASE),
|
||||
Color::fromHex(Defaults::Player::OneCoffeeShirt::PLAYER1_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> one_coffee_shirt = {one_coffee_player0_shirt, one_coffee_player1_shirt};
|
||||
std::array<Shirt, 2> one_coffee_shirt = {ONE_COFFEE_PLAYER0_SHIRT, ONE_COFFEE_PLAYER1_SHIRT};
|
||||
|
||||
const Shirt two_coffee_player0_shirt = Shirt(
|
||||
const Shirt TWO_COFFEE_PLAYER0_SHIRT = Shirt(
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER0_DARKEST),
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER0_DARK),
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER0_BASE),
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER0_LIGHT));
|
||||
|
||||
const Shirt two_coffee_player1_shirt = Shirt(
|
||||
const Shirt TWO_COFFEE_PLAYER1_SHIRT = Shirt(
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER1_DARKEST),
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER1_DARK),
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER1_BASE),
|
||||
Color::fromHex(Defaults::Player::TwoCoffeeShirt::PLAYER1_LIGHT));
|
||||
|
||||
std::array<Shirt, 2> two_coffee_shirt = {two_coffee_player0_shirt, two_coffee_player1_shirt};
|
||||
std::array<Shirt, 2> two_coffee_shirt = {TWO_COFFEE_PLAYER0_SHIRT, TWO_COFFEE_PLAYER1_SHIRT};
|
||||
|
||||
const Color outline_player0_color = Color::fromHex(Defaults::Player::OutlineColor::PLAYER0);
|
||||
const Color outline_player1_color = Color::fromHex(Defaults::Player::OutlineColor::PLAYER1);
|
||||
std::array<Color, 2> outline_color = {outline_player0_color, outline_player1_color};
|
||||
const Color OUTLINE_PLAYER0_COLOR = Color::fromHex(Defaults::Player::OutlineColor::PLAYER0);
|
||||
const Color OUTLINE_PLAYER1_COLOR = Color::fromHex(Defaults::Player::OutlineColor::PLAYER1);
|
||||
std::array<Color, 2> outline_color = {OUTLINE_PLAYER0_COLOR, OUTLINE_PLAYER1_COLOR};
|
||||
};
|
||||
|
||||
// --- Estructura Param: almacena todos los parámetros del juego ---
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <algorithm> // Para clamp, __transform_fn, transform
|
||||
#include <cctype> // Para tolower, isspace
|
||||
#include <cmath> // Para pow, sin, M_PI, cos, sqrt
|
||||
#include <compare> // Para operator<
|
||||
#include <filesystem> // Para path
|
||||
#include <ranges> // Para __find_if_not_fn, find_if_not, reverse_view, __find_fn, find, ref_view
|
||||
#include <string> // Para basic_string, string, allocator, char_traits, operator==, operator+
|
||||
|
||||
Reference in New Issue
Block a user