Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 405f2248ec | |||
| 93b1cd80b7 | |||
| b53bf87730 | |||
| 015a9cc4e1 | |||
| 3bd13b72cd | |||
| c94adf39af | |||
| 950eeffb07 | |||
| b37b62ef1e | |||
| 0c8aa5fe50 | |||
| fe520dd341 | |||
| ec9a9aff81 | |||
| f9c1c4843d | |||
| a804ad1368 | |||
| c689507982 | |||
| 417643018f | |||
| 2ed7316948 | |||
| 2228153d59 | |||
| 7315032ff2 | |||
| 3fc6795593 | |||
| 16924cf503 | |||
| 705a9fc7cd | |||
| b164c11ba7 | |||
| 1817d00881 | |||
| 8dcf473f31 | |||
| 8f191f02fa | |||
| 1077c13fd0 | |||
| d5a4caa86e | |||
| f3bad9f4ed | |||
| 32f22c99db | |||
| cd14ae22c5 | |||
| 1fdc29e9d2 | |||
| 0a740a5be2 | |||
| 9e1b2b8960 | |||
| ed3724193e |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
.cache/
|
.cache/
|
||||||
.vscode/
|
|
||||||
*data/config/config.yaml
|
*data/config/config.yaml
|
||||||
*stats.txt
|
*stats.txt
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
|||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json"
|
||||||
|
}
|
||||||
170
CHANGELOG.md
Normal file
170
CHANGELOG.md
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to JailDoctor's Dilemma are documented here.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.12] - 2026-04-02
|
||||||
|
|
||||||
|
### Novedades
|
||||||
|
- **Color del jugador configurable:** se puede cambiar desde la consola (persistente), con comprobación automática para evitar que coincida con el color de fondo
|
||||||
|
- **Skins de enemigos para el jugador:** posibilidad de usar skins de enemigos en el jugador, con cambio en caliente en el marcador
|
||||||
|
- **Indicador de trucos mejorado:** ya no usa el color del jugador, ahora se muestra en el marcador
|
||||||
|
- **Shader presets por nombre:** se puede establecer un shader preset directamente por nombre desde la consola, con autocompletado
|
||||||
|
- **Comandos externos en consola:** la consola lee los comandos desde un fichero externo
|
||||||
|
- **Gestión de paletas mejorada:**
|
||||||
|
- Nuevas paletas añadidas
|
||||||
|
- Restaurado el orden original de las paletas
|
||||||
|
- Opción de reordenar paletas automáticamente por luminosidad o parecido a la paleta de Spectrum
|
||||||
|
- Nombres "pretty" para las paletas (cambia los `-` por ` `)
|
||||||
|
- Eliminadas responsabilidades de `Options` sobre las paletas
|
||||||
|
- Nueva herramienta en Python para reordenar paletas
|
||||||
|
- **Aceleración hardware configurable:** posibilidad de desactivar la aceleración hardware desde el fichero de configuración; si no hay aceleración, se deshabilitan teclas y comandos de shaders
|
||||||
|
- **Autocompletado mejorado:** shader preset y palette autocompletan con la lista de nombres
|
||||||
|
- Reestructuración de comandos de consola
|
||||||
|
- Reestructuración del apartado de vídeo en `config.yaml`
|
||||||
|
- Optimizaciones en `Surface`
|
||||||
|
|
||||||
|
### Correcciones
|
||||||
|
- Fix: entrar y salir del modo debug mantiene el estado previo del jugador
|
||||||
|
- Corregido Makefile: migración completa a cmake, detección automática de SO para release
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.11] - 2026-03-31
|
||||||
|
|
||||||
|
### Novedades
|
||||||
|
- **PaletteManager:** refactorización de `Screen`, responsabilidades de gestión de paletas extraídas a clase propia
|
||||||
|
- **Consola 2.1:** la consola puede cambiar de paleta por nombre (`Screen` devuelve lista de paletas)
|
||||||
|
- **Zoom configurable:** `Screen` permite establecer el nivel de zoom directamente desde consola
|
||||||
|
- **Autocompletar en consola:** autocompletado de comandos con Tab (incluyendo soporte para armadura de lagarto)
|
||||||
|
- Generación automática de tabla de tab-completions en la consola
|
||||||
|
|
||||||
|
### Correcciones
|
||||||
|
- Fix: al entrar a GAME con la consola abierta, el jugador no tenía los inputs deshabilitados
|
||||||
|
- Fix: al hacer restart con la música del attract mode sonando, la música no paraba al ir al logo
|
||||||
|
- Fix: en modo debug, protección para que el jugador no caiga infinitamente si sale de pantalla
|
||||||
|
- Corregido el case en algunas respuestas de la consola
|
||||||
|
- Corregido Makefile
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.10] - 2026-03-30
|
||||||
|
|
||||||
|
### Novedades
|
||||||
|
- **Consola 2.0:** rediseño completo de la consola de desarrollador
|
||||||
|
- Efecto typewriter al mostrar texto
|
||||||
|
- Separación de líneas automática
|
||||||
|
- Cambio de skin
|
||||||
|
- Historial y navegación mejorada
|
||||||
|
- Comandos para cheats, control de escena, debug, audio y shaders
|
||||||
|
- Teclas de función operativas con la consola abierta
|
||||||
|
- Límite de caracteres ampliado
|
||||||
|
- La consola ya no pausa al jugador
|
||||||
|
- Reorganización del sistema de comandos y aliases (`show info`, `hide info`, etc.)
|
||||||
|
- **RenderInfo:** nueva clase con animación para mostrar info de renderizado en pantalla
|
||||||
|
- **Soporte multi-shader:** comandos y teclas para manejar el nuevo diseño de shaders (SPIRV/SPIR-V)
|
||||||
|
- **Modo kiosko:** defaults y restricciones de comandos para modo kiosk
|
||||||
|
- **Supersampling Lanczos:** implementación de escalado Lanczos en el supersampling
|
||||||
|
- **Driver GPU configurable:** permite elegir driver de GPU o ninguno desde consola
|
||||||
|
- Cheats accesibles desde la consola
|
||||||
|
- Cambio y reinicio de escena desde la consola
|
||||||
|
- Posición e habitación inicial de debug configurables desde consola y fichero
|
||||||
|
- `Debug` carga posición e habitación inicial desde fichero
|
||||||
|
- Comandos de audio configurables desde consola
|
||||||
|
- Renderizado del dispositivo GPU en info_debug
|
||||||
|
- `Screen` optimizado (`textureToRenderer()`)
|
||||||
|
- Eliminado soporte para argumentos de línea de comandos
|
||||||
|
- Eliminado `Options::console`
|
||||||
|
- Help de consola organizado
|
||||||
|
|
||||||
|
### Correcciones
|
||||||
|
- Fix: vsync off no funcionaba en Wayland
|
||||||
|
- Fix: en TITLE, la consola no bloqueaba la pulsación del 1 al 4 y entraba a opciones
|
||||||
|
- Fix: dos logs de consola con formato incorrecto
|
||||||
|
- Fix: lógica para abrir y entrar a la jail (ahora usa número de habitación, no nombre)
|
||||||
|
- Corregido `compile_spirv.cmake` y la `system_folder` para shaders
|
||||||
|
- Corregido carácter de caret que se había perdido
|
||||||
|
- Eliminados acentos en títulos de habitaciones que causaban problemas con fuentes
|
||||||
|
- Revisadas y corregidas traducciones
|
||||||
|
- Corregidos ficheros `.fnt`
|
||||||
|
- Corrección en `Screen` para `std::setprecision()` (faltaba `#include <iomanip>`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.09] - 2025-03-01
|
||||||
|
|
||||||
|
### Novedades
|
||||||
|
- **Refactorización a singletons:** `Screen`, `Input`, `Audio`, `Resource::Cache`, `Resource::List`, `Director`, `Cheevos`, `Debug` convertidos a singletons thread-safe
|
||||||
|
- **Smart pointers:** uso de `std::shared_ptr` y `std::unique_ptr` para gestión de recursos y sprites
|
||||||
|
- **Surfaces 8-bit indexadas:** nuevo sistema de renderizado con color indexado y paletas intercambiables
|
||||||
|
- **Sistema de notificaciones rediseñado:** nuevo engine de notificaciones con control de offset
|
||||||
|
- **Modos de vídeo mejorados:** la ventana mantiene posición al cambiar tamaño o activar borde; puede crecer según el escritorio
|
||||||
|
- **ItemTracker:** nuevo singleton para rastrear ítems recogidos
|
||||||
|
- **globalEvents:** nuevo sistema de eventos globales SDL
|
||||||
|
- **Barra de progreso en carga de recursos** (actualización cada 5 ítems para mayor rendimiento con vsync)
|
||||||
|
- **Métodos show/hide ventana:** métodos para mostrar u ocultar la ventana
|
||||||
|
- Afinada la clase `Options`
|
||||||
|
- Actualizada a la última versión de `jail_audio`
|
||||||
|
- Implementados shaders
|
||||||
|
- Nueva tipografía añadida
|
||||||
|
- Parametros de ficheros `.ani` migrados a snake_case
|
||||||
|
- Música de Title y attract mode restaurada
|
||||||
|
- Eliminado sistema online completo
|
||||||
|
|
||||||
|
### Correcciones
|
||||||
|
- Fix: notificaciones ya no ensucian la pantalla de carga
|
||||||
|
- Fix: no pintaba el efecto de carga del borde en `LoadingScreen`
|
||||||
|
- Fix: bug con el puntero a `ScoreboardData`
|
||||||
|
- Fix: carga de opciones y recursos corregida
|
||||||
|
- Eliminados acentos problemáticos
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.08] - 2024-02-22
|
||||||
|
|
||||||
|
### Novedades
|
||||||
|
- Posibilidad de saltar la pantalla de carga ya completada desde el menú de título
|
||||||
|
- El `gamestate_title` puede empezar en diferentes estados
|
||||||
|
- Pantalla de carga con fade de paleta
|
||||||
|
- GIF loader: dibujado correcto de GIFs en pantalla
|
||||||
|
- Añadida `paleta.cpp`/`.h` y `gif.c`
|
||||||
|
|
||||||
|
### Correcciones
|
||||||
|
- Corregido bug en el fade de paleta (el canal azul no se propagaba)
|
||||||
|
- Arreglada la separación entre el título y el fade
|
||||||
|
- Online deshabilitado por defecto al crear el fichero de configuración
|
||||||
|
- Tiempo de la pantalla de carga aumentado
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.07] - 2022-12-02
|
||||||
|
|
||||||
|
### Novedades
|
||||||
|
- El nombre de la habitación se pinta a partir de una textura
|
||||||
|
- Añadido Batman a FEEL THE HEAT
|
||||||
|
- Cielo de la Jail actualizado
|
||||||
|
- Retocada la pantalla de título
|
||||||
|
- Sprite de PACO modificado
|
||||||
|
- Nombre del enemigo diskette cambiado a floppy
|
||||||
|
- Cambios cosméticos en algunas habitaciones (BE CAREFUL WITH THE FUSE renombrado)
|
||||||
|
- El color de fondo de la habitación se pinta en la textura del mapa
|
||||||
|
- Optimizaciones en intro y title
|
||||||
|
- Preparación para compatibilidad con consolas
|
||||||
|
- Actualizado `jail_audio` a la última versión
|
||||||
|
- Eliminados la mayor parte de accesos a `vector::at()`
|
||||||
|
|
||||||
|
### Correcciones
|
||||||
|
- Corregido bug: en la jail se rellenaban las vidas mientras estaba activa la pausa
|
||||||
|
- Corregido memory leak en `texture.cpp`
|
||||||
|
- Corregido bug en apertura de la Jail
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [v1.0] - 2022-11-13
|
||||||
|
|
||||||
|
Versión de lanzamiento inicial.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*El formato de este changelog sigue [Keep a Changelog](https://keepachangelog.com/).*
|
||||||
@@ -34,31 +34,32 @@ set(APP_SOURCES
|
|||||||
|
|
||||||
# Core - Input
|
# Core - Input
|
||||||
source/core/input/global_inputs.cpp
|
source/core/input/global_inputs.cpp
|
||||||
source/core/input/input.cpp
|
|
||||||
source/core/input/input_types.cpp
|
source/core/input/input_types.cpp
|
||||||
|
source/core/input/input.cpp
|
||||||
source/core/input/mouse.cpp
|
source/core/input/mouse.cpp
|
||||||
|
|
||||||
# Core - Rendering
|
# Core - Rendering
|
||||||
source/core/rendering/gif.cpp
|
source/core/rendering/gif.cpp
|
||||||
|
source/core/rendering/palette_manager.cpp
|
||||||
source/core/rendering/pixel_reveal.cpp
|
source/core/rendering/pixel_reveal.cpp
|
||||||
source/core/rendering/render_info.cpp
|
source/core/rendering/render_info.cpp
|
||||||
source/core/rendering/screen.cpp
|
source/core/rendering/screen.cpp
|
||||||
source/core/rendering/surface.cpp
|
|
||||||
source/core/rendering/sprite/animated_sprite.cpp
|
source/core/rendering/sprite/animated_sprite.cpp
|
||||||
source/core/rendering/sprite/dissolve_sprite.cpp
|
source/core/rendering/sprite/dissolve_sprite.cpp
|
||||||
source/core/rendering/sprite/moving_sprite.cpp
|
source/core/rendering/sprite/moving_sprite.cpp
|
||||||
source/core/rendering/sprite/sprite.cpp
|
source/core/rendering/sprite/sprite.cpp
|
||||||
|
source/core/rendering/surface.cpp
|
||||||
source/core/rendering/text.cpp
|
source/core/rendering/text.cpp
|
||||||
|
|
||||||
# Core - Locale
|
# Core - Locale
|
||||||
source/core/locale/locale.cpp
|
source/core/locale/locale.cpp
|
||||||
|
|
||||||
# Core - Resources
|
# Core - Resources
|
||||||
source/core/resources/resource_list.cpp
|
|
||||||
source/core/resources/resource_cache.cpp
|
source/core/resources/resource_cache.cpp
|
||||||
source/core/resources/resource_pack.cpp
|
|
||||||
source/core/resources/resource_loader.cpp
|
|
||||||
source/core/resources/resource_helper.cpp
|
source/core/resources/resource_helper.cpp
|
||||||
|
source/core/resources/resource_list.cpp
|
||||||
|
source/core/resources/resource_loader.cpp
|
||||||
|
source/core/resources/resource_pack.cpp
|
||||||
|
|
||||||
# Core - System
|
# Core - System
|
||||||
source/core/system/director.cpp
|
source/core/system/director.cpp
|
||||||
@@ -78,9 +79,9 @@ set(APP_SOURCES
|
|||||||
source/game/gameplay/enemy_manager.cpp
|
source/game/gameplay/enemy_manager.cpp
|
||||||
source/game/gameplay/item_manager.cpp
|
source/game/gameplay/item_manager.cpp
|
||||||
source/game/gameplay/item_tracker.cpp
|
source/game/gameplay/item_tracker.cpp
|
||||||
source/game/gameplay/room.cpp
|
|
||||||
source/game/gameplay/room_loader.cpp
|
source/game/gameplay/room_loader.cpp
|
||||||
source/game/gameplay/room_tracker.cpp
|
source/game/gameplay/room_tracker.cpp
|
||||||
|
source/game/gameplay/room.cpp
|
||||||
source/game/gameplay/scoreboard.cpp
|
source/game/gameplay/scoreboard.cpp
|
||||||
source/game/gameplay/stats.cpp
|
source/game/gameplay/stats.cpp
|
||||||
source/game/gameplay/tilemap_renderer.cpp
|
source/game/gameplay/tilemap_renderer.cpp
|
||||||
@@ -89,14 +90,15 @@ set(APP_SOURCES
|
|||||||
source/game/scenes/credits.cpp
|
source/game/scenes/credits.cpp
|
||||||
source/game/scenes/ending.cpp
|
source/game/scenes/ending.cpp
|
||||||
source/game/scenes/ending2.cpp
|
source/game/scenes/ending2.cpp
|
||||||
source/game/scenes/game.cpp
|
|
||||||
source/game/scenes/game_over.cpp
|
source/game/scenes/game_over.cpp
|
||||||
|
source/game/scenes/game.cpp
|
||||||
source/game/scenes/loading_screen.cpp
|
source/game/scenes/loading_screen.cpp
|
||||||
source/game/scenes/logo.cpp
|
source/game/scenes/logo.cpp
|
||||||
source/game/scenes/title.cpp
|
source/game/scenes/title.cpp
|
||||||
|
|
||||||
# Game - UI
|
# Game - UI
|
||||||
source/game/ui/console.cpp
|
source/game/ui/console.cpp
|
||||||
|
source/game/ui/console_commands.cpp
|
||||||
source/game/ui/notifier.cpp
|
source/game/ui/notifier.cpp
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
@@ -223,7 +225,17 @@ if(WIN32)
|
|||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
||||||
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
if(NOT CMAKE_OSX_ARCHITECTURES)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||||
|
endif()
|
||||||
|
if(MACOS_BUNDLE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUNDLE)
|
||||||
|
target_link_options(${PROJECT_NAME} PRIVATE
|
||||||
|
-framework SDL3
|
||||||
|
-F ${CMAKE_SOURCE_DIR}/release/macos/frameworks/SDL3.xcframework/macos-arm64_x86_64
|
||||||
|
-rpath @executable_path/../Frameworks/
|
||||||
|
)
|
||||||
|
endif()
|
||||||
elseif(UNIX AND NOT APPLE)
|
elseif(UNIX AND NOT APPLE)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
287
Makefile
287
Makefile
@@ -18,24 +18,13 @@ RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
|
|||||||
RESOURCE_FILE := release/windows/jdd.res
|
RESOURCE_FILE := release/windows/jdd.res
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# PACKING TOOL
|
# TOOLS
|
||||||
# ==============================================================================
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
PACK_TOOL := $(DIR_TOOLS)pack_resources/pack_resources.exe
|
|
||||||
PACK_CXX := $(CXX)
|
|
||||||
else
|
|
||||||
PACK_TOOL := $(DIR_TOOLS)pack_resources/pack_resources
|
|
||||||
PACK_CXX := $(CXX)
|
|
||||||
endif
|
|
||||||
PACK_SOURCES := $(DIR_TOOLS)pack_resources/pack_resources.cpp source/core/resources/resource_pack.cpp
|
|
||||||
PACK_INCLUDES := -Isource
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
# SHADERS
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
DIR_PACK_TOOL := $(DIR_TOOLS)pack_resources
|
||||||
SHADER_SCRIPT := $(DIR_ROOT)tools/shaders/compile_spirv.sh
|
SHADER_SCRIPT := $(DIR_ROOT)tools/shaders/compile_spirv.sh
|
||||||
SHADER_VERT_H := $(DIR_ROOT)source/core/rendering/sdl3gpu/postfx_vert_spv.h
|
SHADER_CMAKE := $(DIR_ROOT)tools/shaders/compile_spirv.cmake
|
||||||
SHADER_FRAG_H := $(DIR_ROOT)source/core/rendering/sdl3gpu/postfx_frag_spv.h
|
SHADERS_DIR := $(DIR_ROOT)data/shaders
|
||||||
|
HEADERS_DIR := $(DIR_ROOT)source/core/rendering/sdl3gpu
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
GLSLC := $(shell where glslc 2>NUL)
|
GLSLC := $(shell where glslc 2>NUL)
|
||||||
else
|
else
|
||||||
@@ -79,189 +68,87 @@ MACOS_APPLE_SILICON_RELEASE := $(DIST_DIR)/$(TARGET_NAME)-$(VERSION)-macos-apple
|
|||||||
LINUX_RELEASE := $(DIST_DIR)/$(TARGET_NAME)-$(VERSION)-linux.tar.gz
|
LINUX_RELEASE := $(DIST_DIR)/$(TARGET_NAME)-$(VERSION)-linux.tar.gz
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# SOURCE FILES
|
# PLATAFORMA
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
APP_SOURCES := \
|
|
||||||
source/main.cpp \
|
|
||||||
source/core/audio/audio.cpp \
|
|
||||||
source/core/input/input.cpp \
|
|
||||||
source/core/input/input_types.cpp \
|
|
||||||
source/core/input/mouse.cpp \
|
|
||||||
source/core/input/global_inputs.cpp \
|
|
||||||
source/core/rendering/screen.cpp \
|
|
||||||
source/core/rendering/surface.cpp \
|
|
||||||
source/core/rendering/sprite/sprite.cpp \
|
|
||||||
source/core/rendering/sprite/animated_sprite.cpp \
|
|
||||||
source/core/rendering/sprite/moving_sprite.cpp \
|
|
||||||
source/core/rendering/sprite/dissolve_sprite.cpp \
|
|
||||||
source/core/rendering/text.cpp \
|
|
||||||
source/core/rendering/gif.cpp \
|
|
||||||
source/core/rendering/pixel_reveal.cpp \
|
|
||||||
source/core/rendering/render_info.cpp \
|
|
||||||
source/core/rendering/sdl3gpu/sdl3gpu_shader.cpp \
|
|
||||||
source/core/locale/locale.cpp \
|
|
||||||
source/core/resources/resource_list.cpp \
|
|
||||||
source/core/resources/resource_cache.cpp \
|
|
||||||
source/core/resources/resource_helper.cpp \
|
|
||||||
source/core/resources/resource_loader.cpp \
|
|
||||||
source/core/resources/resource_pack.cpp \
|
|
||||||
source/core/system/director.cpp \
|
|
||||||
source/core/system/debug.cpp \
|
|
||||||
source/core/system/global_events.cpp \
|
|
||||||
source/game/options.cpp \
|
|
||||||
source/game/entities/player.cpp \
|
|
||||||
source/game/entities/enemy.cpp \
|
|
||||||
source/game/entities/item.cpp \
|
|
||||||
source/game/gameplay/room.cpp \
|
|
||||||
source/game/gameplay/collision_map.cpp \
|
|
||||||
source/game/gameplay/enemy_manager.cpp \
|
|
||||||
source/game/gameplay/item_manager.cpp \
|
|
||||||
source/game/gameplay/room_loader.cpp \
|
|
||||||
source/game/gameplay/tilemap_renderer.cpp \
|
|
||||||
source/game/gameplay/scoreboard.cpp \
|
|
||||||
source/game/gameplay/cheevos.cpp \
|
|
||||||
source/game/gameplay/item_tracker.cpp \
|
|
||||||
source/game/gameplay/room_tracker.cpp \
|
|
||||||
source/game/gameplay/stats.cpp \
|
|
||||||
source/game/scenes/logo.cpp \
|
|
||||||
source/game/scenes/loading_screen.cpp \
|
|
||||||
source/game/scenes/title.cpp \
|
|
||||||
source/game/scenes/game.cpp \
|
|
||||||
source/game/scenes/game_over.cpp \
|
|
||||||
source/game/scenes/ending.cpp \
|
|
||||||
source/game/scenes/ending2.cpp \
|
|
||||||
source/game/scenes/credits.cpp \
|
|
||||||
source/game/ui/notifier.cpp \
|
|
||||||
source/game/ui/console.cpp \
|
|
||||||
source/utils/utils.cpp \
|
|
||||||
source/utils/delta_timer.cpp
|
|
||||||
|
|
||||||
# All sources combined
|
|
||||||
ALL_SOURCES := $(APP_SOURCES)
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
# INCLUDES
|
|
||||||
# ==============================================================================
|
|
||||||
INCLUDES := -Isource
|
|
||||||
|
|
||||||
# ==============================================================================
|
|
||||||
# COMPILER FLAGS (OS-specific)
|
|
||||||
# ==============================================================================
|
|
||||||
CPP_STANDARD := c++20
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
FixPath = $(subst /,\\,$1)
|
FixPath = $(subst /,\\,$1)
|
||||||
CXXFLAGS := -std=$(CPP_STANDARD) -Wall -Os -ffunction-sections -fdata-sections \
|
|
||||||
-Wl,--gc-sections -static-libstdc++ -static-libgcc \
|
|
||||||
-Wl,-subsystem,windows -DWINDOWS_BUILD
|
|
||||||
CXXFLAGS_DEBUG := -std=$(CPP_STANDARD) -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
|
||||||
LDFLAGS := -lmingw32 -lws2_32 -lSDL3
|
|
||||||
RM := del /Q
|
RM := del /Q
|
||||||
MKDIR := mkdir
|
MKDIR := mkdir
|
||||||
else
|
else
|
||||||
FixPath = $1
|
FixPath = $1
|
||||||
CXXFLAGS := -std=$(CPP_STANDARD) -Wall -Os -ffunction-sections -fdata-sections
|
|
||||||
CXXFLAGS_DEBUG := -std=$(CPP_STANDARD) -Wall -g -D_DEBUG
|
|
||||||
LDFLAGS := -lSDL3
|
|
||||||
RMFILE := rm -f
|
RMFILE := rm -f
|
||||||
RMDIR := rm -rdf
|
RMDIR := rm -rdf
|
||||||
MKDIR := mkdir -p
|
MKDIR := mkdir -p
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
ifeq ($(UNAME_S),Linux)
|
|
||||||
CXXFLAGS += -DLINUX_BUILD
|
|
||||||
endif
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
CXXFLAGS += -DMACOS_BUILD
|
|
||||||
CXXFLAGS_DEBUG += -DMACOS_BUILD
|
|
||||||
# Configurar arquitectura (por defecto arm64)
|
|
||||||
CXXFLAGS += -arch arm64
|
|
||||||
CXXFLAGS_DEBUG += -arch arm64
|
|
||||||
# Usar Apple Clang explícitamente para evitar LLVM de Homebrew
|
|
||||||
MACOS_CXX := /usr/bin/clang++
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# REGLAS PARA COMPILACIÓN DE SHADERS
|
# COMPILACIÓN CON CMAKE
|
||||||
|
# ==============================================================================
|
||||||
|
all:
|
||||||
|
@cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
@cmake --build build
|
||||||
|
|
||||||
|
debug:
|
||||||
|
@cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
@cmake --build build
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# RELEASE AUTOMÁTICO (detecta SO)
|
||||||
|
# ==============================================================================
|
||||||
|
release:
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@"$(MAKE)" windows_release
|
||||||
|
else
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
@$(MAKE) macos_release
|
||||||
|
else
|
||||||
|
@$(MAKE) linux_release
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# REGLAS PARA COMPILACIÓN DE SHADERS (multiplataforma via cmake)
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
compile_shaders:
|
compile_shaders:
|
||||||
ifdef GLSLC
|
ifdef GLSLC
|
||||||
ifeq ($(OS),Windows_NT)
|
@cmake -D GLSLC=$(GLSLC) -D SHADERS_DIR=$(SHADERS_DIR) -D HEADERS_DIR=$(HEADERS_DIR) -P $(SHADER_CMAKE)
|
||||||
@powershell -Command "if ((Test-Path '$(SHADER_VERT_H)') -and (Test-Path '$(SHADER_FRAG_H)')) { Write-Host 'Shaders SPIR-V precompilados OK' } else { Write-Host 'Compilando shaders SPIR-V...'; bash '$(SHADER_SCRIPT)'; Write-Host 'Shaders compilados' }"
|
|
||||||
else
|
else
|
||||||
@echo "Compilando shaders SPIR-V..."
|
@echo "glslc no encontrado - asegurate de que los headers SPIR-V precompilados existen"
|
||||||
@$(SHADER_SCRIPT)
|
|
||||||
@echo "✓ Shaders compilados"
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
@powershell -Command "if ((Test-Path '$(SHADER_VERT_H)') -and (Test-Path '$(SHADER_FRAG_H)')) { Write-Host 'glslc no encontrado - usando headers SPIR-V precompilados' } else { Write-Host 'ERROR: glslc no encontrado y headers SPIR-V no existen.'; Write-Host ' Instala glslc o ejecuta: tools/shaders/compile_spirv.sh'; exit 1 }"
|
|
||||||
else
|
|
||||||
@if [ -f "$(SHADER_VERT_H)" ] && [ -f "$(SHADER_FRAG_H)" ]; then \
|
|
||||||
echo "⚠ glslc no encontrado - usando headers SPIR-V precompilados"; \
|
|
||||||
else \
|
|
||||||
echo "ERROR: glslc no encontrado y headers SPIR-V no existen."; \
|
|
||||||
echo " Instala glslc: sudo apt install glslang-tools"; \
|
|
||||||
echo " O ejecuta manualmente: tools/shaders/compile_spirv.sh"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# REGLAS PARA HERRAMIENTA DE EMPAQUETADO Y RESOURCES.PACK
|
# REGLAS PARA HERRAMIENTA DE EMPAQUETADO Y RESOURCES.PACK
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
$(PACK_TOOL): FORCE
|
pack_tool:
|
||||||
@echo "Compilando herramienta de empaquetado..."
|
@$(MAKE) -C $(DIR_PACK_TOOL)
|
||||||
$(PACK_CXX) -std=$(CPP_STANDARD) -Wall -Os $(PACK_INCLUDES) $(PACK_SOURCES) -o $(PACK_TOOL)
|
|
||||||
@echo "✓ Herramienta de empaquetado lista: $(PACK_TOOL)"
|
|
||||||
|
|
||||||
pack_tool: $(PACK_TOOL)
|
resources.pack: pack_tool
|
||||||
|
@$(MAKE) -C $(DIR_PACK_TOOL) pack
|
||||||
resources.pack: $(PACK_TOOL)
|
|
||||||
@echo "Generando resources.pack desde directorio data/..."
|
|
||||||
$(PACK_TOOL) data resources.pack
|
|
||||||
@echo "✓ resources.pack generado exitosamente"
|
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# COMPILACIÓN PARA WINDOWS
|
# COMPILACIÓN PARA WINDOWS (RELEASE)
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
windows:
|
|
||||||
@echo off
|
|
||||||
@echo Generando version.h...
|
|
||||||
@powershell -Command "$$GIT_HASH = (git rev-parse --short=7 HEAD 2>$$null); if (-not $$GIT_HASH) { $$GIT_HASH = 'unknown' }; (Get-Content source/version.h.in) -replace '@GIT_HASH@', $$GIT_HASH | Set-Content source/version.h"
|
|
||||||
@echo Compilando para Windows con nombre: "$(WIN_TARGET_FILE).exe"
|
|
||||||
windres release/windows/jdd.rc -O coff -o $(RESOURCE_FILE)
|
|
||||||
g++ $(ALL_SOURCES) $(RESOURCE_FILE) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(WIN_TARGET_FILE).exe"
|
|
||||||
strip -s -R .comment -R .gnu.version "$(WIN_TARGET_FILE).exe" --strip-unneeded
|
|
||||||
|
|
||||||
windows_release:
|
windows_release:
|
||||||
@"$(MAKE)" compile_shaders
|
|
||||||
@"$(MAKE)" resources.pack
|
|
||||||
@echo off
|
@echo off
|
||||||
@echo Creando release para Windows - Version: $(VERSION)
|
@echo Creando release para Windows - Version: $(VERSION)
|
||||||
|
|
||||||
# Generate version.h from version.h.in
|
# Compila con cmake (genera shaders, resources.pack y ejecutable)
|
||||||
@echo "Generando version.h..."
|
@cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
@powershell -Command "$$GIT_HASH = (git rev-parse --short=7 HEAD 2>$$null); if (-not $$GIT_HASH) { $$GIT_HASH = 'unknown' }; (Get-Content source/version.h.in) -replace '@GIT_HASH@', $$GIT_HASH | Set-Content source/version.h"
|
@cmake --build build
|
||||||
|
|
||||||
# Crea carpeta de distribución y carpeta temporal 'RELEASE_FOLDER'
|
# Crea carpeta de distribución y carpeta temporal 'RELEASE_FOLDER'
|
||||||
@powershell -Command "if (-not (Test-Path '$(DIST_DIR)')) {New-Item '$(DIST_DIR)' -ItemType Directory}"
|
@powershell -Command "if (-not (Test-Path '$(DIST_DIR)')) {New-Item '$(DIST_DIR)' -ItemType Directory}"
|
||||||
@powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}"
|
@powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}"
|
||||||
@powershell -Command "if (-not (Test-Path '$(RELEASE_FOLDER)')) {New-Item '$(RELEASE_FOLDER)' -ItemType Directory}"
|
@powershell -Command "if (-not (Test-Path '$(RELEASE_FOLDER)')) {New-Item '$(RELEASE_FOLDER)' -ItemType Directory}"
|
||||||
|
|
||||||
# Copia el archivo 'resources.pack'
|
# Copia ficheros
|
||||||
@powershell -Command "Copy-Item -Path 'resources.pack' -Destination '$(RELEASE_FOLDER)'"
|
@powershell -Command "Copy-Item -Path 'resources.pack' -Destination '$(RELEASE_FOLDER)'"
|
||||||
|
|
||||||
# Copia los ficheros que están en la raíz del proyecto
|
|
||||||
@powershell -Command "Copy-Item 'LICENSE' -Destination '$(RELEASE_FOLDER)'"
|
@powershell -Command "Copy-Item 'LICENSE' -Destination '$(RELEASE_FOLDER)'"
|
||||||
@powershell -Command "Copy-Item 'README.md' -Destination '$(RELEASE_FOLDER)'"
|
@powershell -Command "Copy-Item 'README.md' -Destination '$(RELEASE_FOLDER)'"
|
||||||
@powershell -Command "Copy-Item 'gamecontrollerdb.txt' -Destination '$(RELEASE_FOLDER)'"
|
@powershell -Command "Copy-Item 'gamecontrollerdb.txt' -Destination '$(RELEASE_FOLDER)'"
|
||||||
@powershell -Command "Copy-Item 'release\windows\dll\*.dll' -Destination '$(RELEASE_FOLDER)'"
|
@powershell -Command "Copy-Item 'release\windows\dll\*.dll' -Destination '$(RELEASE_FOLDER)'"
|
||||||
|
@powershell -Command "Copy-Item -Path '$(TARGET_FILE)' -Destination '\"$(WIN_RELEASE_FILE).exe\"'"
|
||||||
# Compila (con icono)
|
|
||||||
windres release/windows/jdd.rc -O coff -o $(RESOURCE_FILE)
|
|
||||||
g++ $(ALL_SOURCES) $(RESOURCE_FILE) $(INCLUDES) -DRELEASE_BUILD $(CXXFLAGS) $(LDFLAGS) -o "$(WIN_RELEASE_FILE).exe"
|
|
||||||
strip -s -R .comment -R .gnu.version "$(WIN_RELEASE_FILE).exe" --strip-unneeded
|
strip -s -R .comment -R .gnu.version "$(WIN_RELEASE_FILE).exe" --strip-unneeded
|
||||||
|
|
||||||
# Crea el fichero .zip
|
# Crea el fichero .zip
|
||||||
@@ -273,31 +160,24 @@ windows_release:
|
|||||||
@powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}"
|
@powershell -Command "if (Test-Path '$(RELEASE_FOLDER)') {Remove-Item '$(RELEASE_FOLDER)' -Recurse -Force}"
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# COMPILACIÓN PARA MACOS
|
# COMPILACIÓN PARA MACOS (RELEASE)
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
macos:
|
|
||||||
@GIT_HASH=$$(git rev-parse --short=7 HEAD 2>/dev/null || echo "unknown"); \
|
|
||||||
sed "s/@GIT_HASH@/$$GIT_HASH/g" source/version.h.in > source/version.h
|
|
||||||
@echo "Compilando para macOS: $(TARGET_NAME)"
|
|
||||||
$(MACOS_CXX) $(ALL_SOURCES) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)"
|
|
||||||
|
|
||||||
macos_release:
|
macos_release:
|
||||||
@$(MAKE) compile_shaders
|
|
||||||
@$(MAKE) resources.pack
|
|
||||||
@echo "Creando release para macOS - Version: $(VERSION)"
|
@echo "Creando release para macOS - Version: $(VERSION)"
|
||||||
|
|
||||||
# Verificar e instalar create-dmg si es necesario
|
# Verificar e instalar create-dmg si es necesario
|
||||||
@which create-dmg > /dev/null || (echo "Instalando create-dmg..." && brew install create-dmg)
|
@which create-dmg > /dev/null || (echo "Instalando create-dmg..." && brew install create-dmg)
|
||||||
|
|
||||||
# Generate version.h from version.h.in
|
# Compila la versión para procesadores Intel con cmake (genera shaders y resources.pack)
|
||||||
@echo "Generando version.h..."
|
@cmake -S . -B build/intel -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DMACOS_BUNDLE=ON
|
||||||
@GIT_HASH=$$(git rev-parse --short=7 HEAD 2>/dev/null || echo "unknown"); \
|
@cmake --build build/intel
|
||||||
sed "s/@GIT_HASH@/$$GIT_HASH/g" source/version.h.in > source/version.h
|
|
||||||
|
|
||||||
# Elimina datos de compilaciones anteriores
|
# Elimina datos de compilaciones anteriores
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
$(RMFILE) tmp.dmg
|
$(RMFILE) tmp.dmg
|
||||||
$(RMFILE) "$(DIST_DIR)"/rw.*
|
$(RMFILE) "$(DIST_DIR)"/rw.*
|
||||||
|
$(RMFILE) "$(MACOS_INTEL_RELEASE)"
|
||||||
|
$(RMFILE) "$(MACOS_APPLE_SILICON_RELEASE)"
|
||||||
|
|
||||||
# Crea la carpeta temporal para hacer el trabajo y las carpetas obligatorias para crear una app de macOS
|
# Crea la carpeta temporal para hacer el trabajo y las carpetas obligatorias para crear una app de macOS
|
||||||
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||||
@@ -319,8 +199,8 @@ macos_release:
|
|||||||
sed -i '' '/<key>CFBundleShortVersionString<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \
|
sed -i '' '/<key>CFBundleShortVersionString<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \
|
||||||
sed -i '' '/<key>CFBundleVersion<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"
|
sed -i '' '/<key>CFBundleVersion<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"
|
||||||
|
|
||||||
# Compila la versión para procesadores Intel
|
# Copia el ejecutable Intel al bundle
|
||||||
$(MACOS_CXX) $(ALL_SOURCES) $(INCLUDES) -DMACOS_BUNDLE -DRELEASE_BUILD -std=$(CPP_STANDARD) -Wall -Os -framework SDL3 -F release/macos/frameworks/SDL3.xcframework/macos-arm64_x86_64 -ffunction-sections -fdata-sections -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.15
|
cp "$(TARGET_FILE)" "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)"
|
||||||
|
|
||||||
# Firma la aplicación
|
# Firma la aplicación
|
||||||
codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
||||||
@@ -342,8 +222,10 @@ macos_release:
|
|||||||
"$(RELEASE_FOLDER)" || true
|
"$(RELEASE_FOLDER)" || true
|
||||||
@echo "Release Intel creado: $(MACOS_INTEL_RELEASE)"
|
@echo "Release Intel creado: $(MACOS_INTEL_RELEASE)"
|
||||||
|
|
||||||
# Compila la versión para procesadores Apple Silicon
|
# Compila la versión para procesadores Apple Silicon con cmake
|
||||||
$(MACOS_CXX) $(ALL_SOURCES) $(INCLUDES) -DMACOS_BUNDLE -DRELEASE_BUILD -std=$(CPP_STANDARD) -Wall -Os -framework SDL3 -F release/macos/frameworks/SDL3.xcframework/macos-arm64_x86_64 -ffunction-sections -fdata-sections -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11
|
@cmake -S . -B build/arm -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 -DMACOS_BUNDLE=ON
|
||||||
|
@cmake --build build/arm
|
||||||
|
cp "$(TARGET_FILE)" "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)"
|
||||||
|
|
||||||
# Firma la aplicación
|
# Firma la aplicación
|
||||||
codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
||||||
@@ -367,27 +249,19 @@ macos_release:
|
|||||||
|
|
||||||
# Elimina las carpetas temporales
|
# Elimina las carpetas temporales
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
$(RMDIR) build/intel
|
||||||
|
$(RMDIR) build/arm
|
||||||
$(RMFILE) "$(DIST_DIR)"/rw.*
|
$(RMFILE) "$(DIST_DIR)"/rw.*
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# COMPILACIÓN PARA LINUX
|
# COMPILACIÓN PARA LINUX (RELEASE)
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
linux:
|
|
||||||
@GIT_HASH=$$(git rev-parse --short=7 HEAD 2>/dev/null || echo "unknown"); \
|
|
||||||
sed "s/@GIT_HASH@/$$GIT_HASH/g" source/version.h.in > source/version.h
|
|
||||||
@echo "Compilando para Linux: $(TARGET_NAME)"
|
|
||||||
g++ $(ALL_SOURCES) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)"
|
|
||||||
strip -s -R .comment -R .gnu.version "$(TARGET_FILE)" --strip-unneeded
|
|
||||||
|
|
||||||
linux_release:
|
linux_release:
|
||||||
@$(MAKE) compile_shaders
|
|
||||||
@$(MAKE) resources.pack
|
|
||||||
@echo "Creando release para Linux - Version: $(VERSION)"
|
@echo "Creando release para Linux - Version: $(VERSION)"
|
||||||
|
|
||||||
# Generate version.h from version.h.in
|
# Compila con cmake (genera shaders, resources.pack y ejecutable)
|
||||||
@echo "Generando version.h..."
|
@cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
@GIT_HASH=$$(git rev-parse --short=7 HEAD 2>/dev/null || echo "unknown"); \
|
@cmake --build build
|
||||||
sed "s/@GIT_HASH@/$$GIT_HASH/g" source/version.h.in > source/version.h
|
|
||||||
|
|
||||||
# Elimina carpeta temporal previa y la recrea (crea dist/ si no existe)
|
# Elimina carpeta temporal previa y la recrea (crea dist/ si no existe)
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
@@ -398,9 +272,7 @@ linux_release:
|
|||||||
cp LICENSE "$(RELEASE_FOLDER)"
|
cp LICENSE "$(RELEASE_FOLDER)"
|
||||||
cp README.md "$(RELEASE_FOLDER)"
|
cp README.md "$(RELEASE_FOLDER)"
|
||||||
cp gamecontrollerdb.txt "$(RELEASE_FOLDER)"
|
cp gamecontrollerdb.txt "$(RELEASE_FOLDER)"
|
||||||
|
cp "$(TARGET_FILE)" "$(RELEASE_FILE)"
|
||||||
# Compila
|
|
||||||
g++ $(ALL_SOURCES) $(INCLUDES) -DRELEASE_BUILD $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE)"
|
|
||||||
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded
|
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded
|
||||||
|
|
||||||
# Empaqueta ficheros
|
# Empaqueta ficheros
|
||||||
@@ -422,17 +294,24 @@ show_version:
|
|||||||
help:
|
help:
|
||||||
@echo "Makefile para JailDoctor's Dilemma"
|
@echo "Makefile para JailDoctor's Dilemma"
|
||||||
@echo "Comandos disponibles:"
|
@echo "Comandos disponibles:"
|
||||||
@echo " windows - Compilar para Windows"
|
@echo ""
|
||||||
@echo " windows_release - Crear release completo para Windows"
|
@echo " Compilacion:"
|
||||||
@echo " linux - Compilar para Linux"
|
@echo " make - Compilar con cmake (Release)"
|
||||||
@echo " linux_release - Crear release completo para Linux"
|
@echo " make debug - Compilar con cmake (Debug)"
|
||||||
@echo " macos - Compilar para macOS"
|
@echo ""
|
||||||
@echo " macos_release - Crear release completo para macOS"
|
@echo " Release:"
|
||||||
@echo " pack_tool - Compilar herramienta de empaquetado"
|
@echo " make release - Crear release (detecta SO automaticamente)"
|
||||||
@echo " resources.pack - Generar pack de recursos desde data/"
|
@echo " make windows_release - Crear release para Windows"
|
||||||
@echo " show_version - Mostrar version actual ($(VERSION))"
|
@echo " make linux_release - Crear release para Linux"
|
||||||
@echo " help - Mostrar esta ayuda"
|
@echo " make macos_release - Crear release para macOS"
|
||||||
|
@echo ""
|
||||||
|
@echo " Herramientas:"
|
||||||
|
@echo " make compile_shaders - Compilar shaders SPIR-V"
|
||||||
|
@echo " make pack_tool - Compilar herramienta de empaquetado"
|
||||||
|
@echo " make resources.pack - Generar pack de recursos desde data/"
|
||||||
|
@echo ""
|
||||||
|
@echo " Otros:"
|
||||||
|
@echo " make show_version - Mostrar version actual ($(VERSION))"
|
||||||
|
@echo " make help - Mostrar esta ayuda"
|
||||||
|
|
||||||
FORCE:
|
.PHONY: all debug release windows_release macos_release linux_release compile_shaders pack_tool resources.pack show_version help
|
||||||
|
|
||||||
.PHONY: windows windows_release macos macos_release linux linux_release compile_shaders pack_tool resources.pack show_version help
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ assets:
|
|||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/zx-spectrum-adjusted.pal
|
path: ${PREFIX}/data/palette/zx-spectrum-adjusted.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/zxarne-5-2.pal
|
path: ${PREFIX}/data/palette/zxarne-5.2.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/black-and-white.pal
|
path: ${PREFIX}/data/palette/black-and-white.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
@@ -46,15 +46,33 @@ assets:
|
|||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/pico-8.pal
|
path: ${PREFIX}/data/palette/pico-8.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/sweetie-16.pal
|
path: ${PREFIX}/data/palette/sweetie.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/island-joy-16.pal
|
path: ${PREFIX}/data/palette/island-joy.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/lost-century.pal
|
path: ${PREFIX}/data/palette/lost-century.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/na16.pal
|
path: ${PREFIX}/data/palette/na.pal
|
||||||
- type: PALETTE
|
- type: PALETTE
|
||||||
path: ${PREFIX}/data/palette/steam-lords.pal
|
path: ${PREFIX}/data/palette/steam-lords.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/winds-seed-pc98.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/psychic-fibre.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/shido-cyberneon.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/darkseed.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/antiquity.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/bubblegum.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/vanilla-milkshake.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/aged-terracotta.pal
|
||||||
|
- type: PALETTE
|
||||||
|
path: ${PREFIX}/data/palette/h16da.pal
|
||||||
|
|
||||||
# LOCALE
|
# LOCALE
|
||||||
locale:
|
locale:
|
||||||
@@ -99,6 +117,11 @@ assets:
|
|||||||
required: false
|
required: false
|
||||||
absolute: true
|
absolute: true
|
||||||
|
|
||||||
|
# CONSOLE
|
||||||
|
console:
|
||||||
|
- type: DATA
|
||||||
|
path: ${PREFIX}/data/console/commands.yaml
|
||||||
|
|
||||||
# ROOMS
|
# ROOMS
|
||||||
rooms:
|
rooms:
|
||||||
- type: ROOM
|
- type: ROOM
|
||||||
|
|||||||
232
data/console/commands.yaml
Normal file
232
data/console/commands.yaml
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
# JailDoctor's Dilemma - Console Commands
|
||||||
|
# Metadata for the in-game console command system.
|
||||||
|
# Execution logic stays in C++; this file defines metadata only.
|
||||||
|
#
|
||||||
|
# Fields:
|
||||||
|
# keyword - Command name (uppercase)
|
||||||
|
# handler - C++ handler function identifier
|
||||||
|
# description - Short description for help output
|
||||||
|
# usage - Full usage string for terminal help
|
||||||
|
# instant - (optional) Skip typewriter effect (default: false)
|
||||||
|
# hidden - (optional) Hide from TAB completion (default: false)
|
||||||
|
# debug_only - (optional) Only available in debug builds (default: false)
|
||||||
|
# help_hidden - (optional) Don't show in help output (default: false)
|
||||||
|
# dynamic_completions - (optional) Completions generated at runtime (default: false)
|
||||||
|
# completions - (optional) Static TAB completion tree
|
||||||
|
# debug_extras - (optional) Overrides applied in debug builds
|
||||||
|
|
||||||
|
categories:
|
||||||
|
- name: VIDEO
|
||||||
|
commands:
|
||||||
|
- keyword: SS
|
||||||
|
handler: cmd_ss
|
||||||
|
description: Supersampling
|
||||||
|
usage: "SS [ON|OFF|SIZE|UPSCALE [NEAREST|LINEAR]|DOWNSCALE [BILINEAR|LANCZOS2|LANCZOS3]]"
|
||||||
|
completions:
|
||||||
|
SS: [ON, OFF, SIZE, UPSCALE, DOWNSCALE]
|
||||||
|
SS UPSCALE: [NEAREST, LINEAR]
|
||||||
|
SS DOWNSCALE: [BILINEAR, LANCZOS2, LANCZOS3]
|
||||||
|
|
||||||
|
- keyword: SHADER
|
||||||
|
handler: cmd_shader
|
||||||
|
description: "Toggle/select shader (F4)"
|
||||||
|
usage: "SHADER [ON|OFF|NEXT|POSTFX|CRTPI|PRESET [NEXT|PREV|<name>]]"
|
||||||
|
completions:
|
||||||
|
SHADER: [ON, OFF, NEXT, POSTFX, CRTPI, PRESET]
|
||||||
|
dynamic_completions: true
|
||||||
|
|
||||||
|
- keyword: BORDER
|
||||||
|
handler: cmd_border
|
||||||
|
description: "Decorative border (B)"
|
||||||
|
usage: "BORDER [ON|OFF]"
|
||||||
|
completions:
|
||||||
|
BORDER: [ON, OFF]
|
||||||
|
|
||||||
|
- keyword: FULLSCREEN
|
||||||
|
handler: cmd_fullscreen
|
||||||
|
description: "Fullscreen mode (F3)"
|
||||||
|
usage: "FULLSCREEN [ON|OFF]"
|
||||||
|
completions:
|
||||||
|
FULLSCREEN: [ON, OFF]
|
||||||
|
|
||||||
|
- keyword: ZOOM
|
||||||
|
handler: cmd_zoom
|
||||||
|
description: "Window zoom (F1/F2)"
|
||||||
|
usage: "ZOOM [UP|DOWN|<1-N>]"
|
||||||
|
completions:
|
||||||
|
ZOOM: [UP, DOWN]
|
||||||
|
|
||||||
|
- keyword: INTSCALE
|
||||||
|
handler: cmd_intscale
|
||||||
|
description: "Integer scaling (F7)"
|
||||||
|
usage: "INTSCALE [ON|OFF]"
|
||||||
|
completions:
|
||||||
|
INTSCALE: [ON, OFF]
|
||||||
|
|
||||||
|
- keyword: VSYNC
|
||||||
|
handler: cmd_vsync
|
||||||
|
description: "Vertical sync"
|
||||||
|
usage: "VSYNC [ON|OFF]"
|
||||||
|
completions:
|
||||||
|
VSYNC: [ON, OFF]
|
||||||
|
|
||||||
|
- keyword: DRIVER
|
||||||
|
handler: cmd_driver
|
||||||
|
description: "GPU driver (restart to apply)"
|
||||||
|
usage: "DRIVER [LIST|AUTO|NONE|<name>]"
|
||||||
|
completions:
|
||||||
|
DRIVER: [LIST, AUTO, NONE]
|
||||||
|
|
||||||
|
- keyword: PALETTE
|
||||||
|
handler: cmd_palette
|
||||||
|
description: "Color palette (F5/F6)"
|
||||||
|
usage: "PALETTE [NEXT|PREV|SORT [ORIGINAL|LUMINANCE|SPECTRUM]|DEFAULT|<name>]"
|
||||||
|
completions:
|
||||||
|
PALETTE SORT: [ORIGINAL, LUMINANCE, SPECTRUM]
|
||||||
|
dynamic_completions: true
|
||||||
|
|
||||||
|
- name: AUDIO
|
||||||
|
commands:
|
||||||
|
- keyword: AUDIO
|
||||||
|
handler: cmd_audio
|
||||||
|
description: Audio master
|
||||||
|
usage: "AUDIO [ON|OFF|VOL <0-100>]"
|
||||||
|
completions:
|
||||||
|
AUDIO: [ON, OFF, VOL]
|
||||||
|
|
||||||
|
- keyword: MUSIC
|
||||||
|
handler: cmd_music
|
||||||
|
description: Music volume
|
||||||
|
usage: "MUSIC [ON|OFF|VOL <0-100>]"
|
||||||
|
completions:
|
||||||
|
MUSIC: [ON, OFF, VOL]
|
||||||
|
|
||||||
|
- keyword: SOUND
|
||||||
|
handler: cmd_sound
|
||||||
|
description: Sound volume
|
||||||
|
usage: "SOUND [ON|OFF|VOL <0-100>]"
|
||||||
|
completions:
|
||||||
|
SOUND: [ON, OFF, VOL]
|
||||||
|
|
||||||
|
- name: GAME
|
||||||
|
commands:
|
||||||
|
- keyword: PLAYER
|
||||||
|
handler: cmd_player
|
||||||
|
description: "Player skin and color"
|
||||||
|
usage: "PLAYER SKIN <name> | PLAYER COLOR <0-15>|DEFAULT"
|
||||||
|
completions:
|
||||||
|
PLAYER: [SKIN, COLOR]
|
||||||
|
PLAYER SKIN: [DEFAULT, ABAD, BATMAN, CHIP, CONGO, JEANNINE, MUMMY, UPV_STUDENT]
|
||||||
|
PLAYER COLOR: [DEFAULT]
|
||||||
|
|
||||||
|
- keyword: RESTART
|
||||||
|
handler: cmd_restart
|
||||||
|
description: Restart from the beginning
|
||||||
|
usage: RESTART
|
||||||
|
instant: true
|
||||||
|
|
||||||
|
- keyword: KIOSK
|
||||||
|
handler: cmd_kiosk
|
||||||
|
description: Enable kiosk mode
|
||||||
|
usage: "KIOSK [ON]"
|
||||||
|
completions:
|
||||||
|
KIOSK: [ON]
|
||||||
|
|
||||||
|
- keyword: EXIT
|
||||||
|
handler: cmd_exit
|
||||||
|
description: Quit application
|
||||||
|
usage: EXIT
|
||||||
|
instant: true
|
||||||
|
|
||||||
|
- keyword: QUIT
|
||||||
|
handler: cmd_quit
|
||||||
|
description: Quit application
|
||||||
|
usage: QUIT
|
||||||
|
instant: true
|
||||||
|
help_hidden: true
|
||||||
|
|
||||||
|
- name: INFO
|
||||||
|
commands:
|
||||||
|
- keyword: SHOW
|
||||||
|
handler: cmd_show
|
||||||
|
description: Show info overlay
|
||||||
|
usage: "SHOW [INFO]"
|
||||||
|
completions:
|
||||||
|
SHOW: [INFO]
|
||||||
|
debug_extras:
|
||||||
|
description: "Show overlay/test notification"
|
||||||
|
usage: "SHOW [INFO|NOTIFICATION|CHEEVO]"
|
||||||
|
completions:
|
||||||
|
SHOW: [INFO, NOTIFICATION, CHEEVO]
|
||||||
|
|
||||||
|
- keyword: HIDE
|
||||||
|
handler: cmd_hide
|
||||||
|
description: Hide info overlay
|
||||||
|
usage: "HIDE [INFO]"
|
||||||
|
completions:
|
||||||
|
HIDE: [INFO]
|
||||||
|
|
||||||
|
- keyword: SIZE
|
||||||
|
handler: cmd_size
|
||||||
|
description: Window size in pixels
|
||||||
|
usage: SIZE
|
||||||
|
|
||||||
|
- keyword: HELP
|
||||||
|
handler: cmd_help
|
||||||
|
description: "Show this help"
|
||||||
|
usage: "HELP / ?"
|
||||||
|
|
||||||
|
- keyword: "?"
|
||||||
|
handler: cmd_help
|
||||||
|
help_hidden: true
|
||||||
|
|
||||||
|
- name: DEBUG
|
||||||
|
debug_only: true
|
||||||
|
commands:
|
||||||
|
- keyword: DEBUG
|
||||||
|
handler: cmd_debug
|
||||||
|
description: "Debug mode and start options (F12)"
|
||||||
|
usage: "DEBUG [MODE [ON|OFF]|START [HERE|ROOM|POS|SCENE <name>]]"
|
||||||
|
completions:
|
||||||
|
DEBUG: [MODE, START]
|
||||||
|
DEBUG MODE: [ON, OFF]
|
||||||
|
DEBUG START: [HERE, ROOM, POS, SCENE]
|
||||||
|
DEBUG START SCENE: [LOGO, LOADING, TITLE, CREDITS, GAME, ENDING, ENDING2]
|
||||||
|
|
||||||
|
- keyword: ITEMS
|
||||||
|
handler: cmd_items
|
||||||
|
description: "Set item count (GAME only)"
|
||||||
|
usage: "ITEMS <0-200>"
|
||||||
|
|
||||||
|
- keyword: ROOM
|
||||||
|
handler: cmd_room
|
||||||
|
description: "Change to room number (GAME only)"
|
||||||
|
usage: "ROOM <1-60>|NEXT|PREV"
|
||||||
|
completions:
|
||||||
|
ROOM: [NEXT, PREV]
|
||||||
|
|
||||||
|
- keyword: SCENE
|
||||||
|
handler: cmd_scene
|
||||||
|
description: Change scene
|
||||||
|
usage: "SCENE [LOGO|LOADING|TITLE|CREDITS|GAME|ENDING|ENDING2|RESTART]"
|
||||||
|
completions:
|
||||||
|
SCENE: [LOGO, LOADING, TITLE, CREDITS, GAME, ENDING, ENDING2, RESTART]
|
||||||
|
|
||||||
|
- name: CHEATS
|
||||||
|
commands:
|
||||||
|
- keyword: CHEAT
|
||||||
|
handler: cmd_cheat
|
||||||
|
description: "Game cheats (GAME only)"
|
||||||
|
usage: "CHEAT [INFINITE LIVES|INVINCIBILITY|OPEN THE JAIL|CLOSE THE JAIL]"
|
||||||
|
hidden: true
|
||||||
|
completions:
|
||||||
|
CHEAT: [INFINITE, INVINCIBILITY, OPEN, CLOSE]
|
||||||
|
CHEAT INFINITE: [LIVES]
|
||||||
|
CHEAT INFINITE LIVES: [ON, OFF]
|
||||||
|
CHEAT INVINCIBILITY: [ON, OFF]
|
||||||
|
CHEAT OPEN: [THE]
|
||||||
|
CHEAT OPEN THE: [JAIL]
|
||||||
|
CHEAT CLOSE: [THE]
|
||||||
|
CHEAT CLOSE THE: [JAIL]
|
||||||
|
debug_extras:
|
||||||
|
hidden: false
|
||||||
@@ -116,6 +116,7 @@ ui:
|
|||||||
supersampling_enabled: "SUPERMOSTREIG ACTIVAT"
|
supersampling_enabled: "SUPERMOSTREIG ACTIVAT"
|
||||||
supersampling_disabled: "SUPERMOSTREIG DESACTIVAT"
|
supersampling_disabled: "SUPERMOSTREIG DESACTIVAT"
|
||||||
palette: "PALETA"
|
palette: "PALETA"
|
||||||
|
palette_sort: "ORDENACIÓ PALETA"
|
||||||
integer_scale_enabled: "ESCALAT SENCER ACTIVAT"
|
integer_scale_enabled: "ESCALAT SENCER ACTIVAT"
|
||||||
integer_scale_disabled: "ESCALAT SENCER DESACTIVAT"
|
integer_scale_disabled: "ESCALAT SENCER DESACTIVAT"
|
||||||
vsync_enabled: "V-SYNC ACTIVAT"
|
vsync_enabled: "V-SYNC ACTIVAT"
|
||||||
@@ -125,6 +126,8 @@ scoreboard:
|
|||||||
items: "TRESORS PILLATS "
|
items: "TRESORS PILLATS "
|
||||||
time: " HORA "
|
time: " HORA "
|
||||||
rooms: "SALES"
|
rooms: "SALES"
|
||||||
|
cheat_infinite_lives: "vides inf"
|
||||||
|
cheat_invincibility: "inv"
|
||||||
|
|
||||||
game:
|
game:
|
||||||
music_enabled: "MÚSICA ACTIVADA"
|
music_enabled: "MÚSICA ACTIVADA"
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ ui:
|
|||||||
supersampling_enabled: "SUPERSAMPLING ON"
|
supersampling_enabled: "SUPERSAMPLING ON"
|
||||||
supersampling_disabled: "SUPERSAMPLING OFF"
|
supersampling_disabled: "SUPERSAMPLING OFF"
|
||||||
palette: "PALETTE"
|
palette: "PALETTE"
|
||||||
|
palette_sort: "PALETTE SORT"
|
||||||
integer_scale_enabled: "INTEGER SCALE ENABLED"
|
integer_scale_enabled: "INTEGER SCALE ENABLED"
|
||||||
integer_scale_disabled: "INTEGER SCALE DISABLED"
|
integer_scale_disabled: "INTEGER SCALE DISABLED"
|
||||||
vsync_enabled: "V-SYNC ENABLED"
|
vsync_enabled: "V-SYNC ENABLED"
|
||||||
@@ -125,6 +126,8 @@ scoreboard:
|
|||||||
items: "ITEMS COLLECTED "
|
items: "ITEMS COLLECTED "
|
||||||
time: " TIME "
|
time: " TIME "
|
||||||
rooms: "ROOMS"
|
rooms: "ROOMS"
|
||||||
|
cheat_infinite_lives: "inf lives"
|
||||||
|
cheat_invincibility: "inv"
|
||||||
|
|
||||||
game:
|
game:
|
||||||
music_enabled: "MUSIC ENABLED"
|
music_enabled: "MUSIC ENABLED"
|
||||||
|
|||||||
19
data/palette/aged-terracotta.pal
Normal file
19
data/palette/aged-terracotta.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
52 49 40
|
||||||
|
80 73 57
|
||||||
|
92 104 82
|
||||||
|
108 116 76
|
||||||
|
125 130 73
|
||||||
|
163 158 85
|
||||||
|
202 181 103
|
||||||
|
119 63 53
|
||||||
|
132 86 64
|
||||||
|
160 119 84
|
||||||
|
188 153 120
|
||||||
|
214 193 157
|
||||||
|
234 220 193
|
||||||
|
247 240 221
|
||||||
|
255 251 237
|
||||||
|
255 255 255
|
||||||
19
data/palette/antiquity.pal
Normal file
19
data/palette/antiquity.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
32 32 32
|
||||||
|
45 33 30
|
||||||
|
69 41 35
|
||||||
|
109 61 41
|
||||||
|
177 107 74
|
||||||
|
232 159 110
|
||||||
|
232 190 130
|
||||||
|
93 117 87
|
||||||
|
142 146 87
|
||||||
|
112 123 136
|
||||||
|
138 167 172
|
||||||
|
229 93 77
|
||||||
|
241 134 108
|
||||||
|
210 103 48
|
||||||
|
222 154 40
|
||||||
|
232 216 165
|
||||||
19
data/palette/bubblegum.pal
Normal file
19
data/palette/bubblegum.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
22 23 26
|
||||||
|
127 6 34
|
||||||
|
214 36 17
|
||||||
|
255 132 38
|
||||||
|
255 209 0
|
||||||
|
250 253 255
|
||||||
|
255 128 164
|
||||||
|
255 38 116
|
||||||
|
148 33 106
|
||||||
|
67 0 103
|
||||||
|
35 73 117
|
||||||
|
104 174 212
|
||||||
|
191 255 60
|
||||||
|
16 210 117
|
||||||
|
0 120 153
|
||||||
|
0 40 89
|
||||||
19
data/palette/darkseed.pal
Normal file
19
data/palette/darkseed.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
0 0 0
|
||||||
|
0 20 24
|
||||||
|
0 32 36
|
||||||
|
0 44 56
|
||||||
|
20 52 68
|
||||||
|
68 52 68
|
||||||
|
88 60 72
|
||||||
|
108 76 68
|
||||||
|
128 96 88
|
||||||
|
108 112 108
|
||||||
|
136 128 120
|
||||||
|
164 148 132
|
||||||
|
196 172 156
|
||||||
|
216 176 168
|
||||||
|
236 212 208
|
||||||
|
252 252 252
|
||||||
19
data/palette/h16da.pal
Normal file
19
data/palette/h16da.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
226 217 228
|
||||||
|
108 154 154
|
||||||
|
82 103 93
|
||||||
|
55 64 59
|
||||||
|
243 200 147
|
||||||
|
229 152 125
|
||||||
|
203 94 92
|
||||||
|
114 51 76
|
||||||
|
192 165 169
|
||||||
|
191 125 133
|
||||||
|
128 77 83
|
||||||
|
64 48 56
|
||||||
|
124 143 178
|
||||||
|
76 82 116
|
||||||
|
46 51 77
|
||||||
|
31 32 37
|
||||||
19
data/palette/psychic-fibre.pal
Normal file
19
data/palette/psychic-fibre.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
10 8 25
|
||||||
|
49 50 67
|
||||||
|
69 59 70
|
||||||
|
87 84 117
|
||||||
|
130 105 128
|
||||||
|
164 111 114
|
||||||
|
185 115 113
|
||||||
|
205 95 105
|
||||||
|
229 76 81
|
||||||
|
201 55 73
|
||||||
|
144 161 168
|
||||||
|
140 147 137
|
||||||
|
195 150 145
|
||||||
|
236 151 134
|
||||||
|
235 171 145
|
||||||
|
219 182 167
|
||||||
19
data/palette/shido-cyberneon.pal
Normal file
19
data/palette/shido-cyberneon.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
0 3 60
|
||||||
|
0 82 96
|
||||||
|
0 157 74
|
||||||
|
10 255 82
|
||||||
|
0 56 132
|
||||||
|
0 138 197
|
||||||
|
0 247 255
|
||||||
|
255 92 255
|
||||||
|
172 41 206
|
||||||
|
96 0 136
|
||||||
|
177 5 133
|
||||||
|
255 0 78
|
||||||
|
42 46 121
|
||||||
|
78 110 168
|
||||||
|
173 212 250
|
||||||
|
255 255 255
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
JASC-PAL
|
|
||||||
0100
|
|
||||||
16
|
|
||||||
26 28 44
|
|
||||||
93 39 93
|
|
||||||
177 62 83
|
|
||||||
239 125 87
|
|
||||||
255 205 117
|
|
||||||
167 240 112
|
|
||||||
56 183 100
|
|
||||||
37 113 121
|
|
||||||
41 54 111
|
|
||||||
59 93 201
|
|
||||||
65 166 246
|
|
||||||
115 239 247
|
|
||||||
244 244 244
|
|
||||||
148 176 194
|
|
||||||
86 108 134
|
|
||||||
51 60 87
|
|
||||||
@@ -2,18 +2,18 @@ JASC-PAL
|
|||||||
0100
|
0100
|
||||||
16
|
16
|
||||||
26 28 44
|
26 28 44
|
||||||
41 54 111
|
|
||||||
51 60 87
|
|
||||||
86 108 134
|
|
||||||
59 93 201
|
|
||||||
37 113 121
|
|
||||||
93 39 93
|
93 39 93
|
||||||
177 62 83
|
177 62 83
|
||||||
56 183 100
|
|
||||||
167 240 112
|
|
||||||
65 166 246
|
|
||||||
115 239 247
|
|
||||||
239 125 87
|
239 125 87
|
||||||
255 205 117
|
255 205 117
|
||||||
148 176 194
|
167 240 112
|
||||||
|
56 183 100
|
||||||
|
37 113 121
|
||||||
|
41 54 111
|
||||||
|
59 93 201
|
||||||
|
65 166 246
|
||||||
|
115 239 247
|
||||||
244 244 244
|
244 244 244
|
||||||
|
148 176 194
|
||||||
|
86 108 134
|
||||||
|
51 60 87
|
||||||
19
data/palette/vanilla-milkshake.pal
Normal file
19
data/palette/vanilla-milkshake.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
40 40 46
|
||||||
|
108 86 113
|
||||||
|
217 200 191
|
||||||
|
249 130 132
|
||||||
|
176 169 228
|
||||||
|
172 204 228
|
||||||
|
179 227 218
|
||||||
|
254 170 228
|
||||||
|
135 168 137
|
||||||
|
176 235 147
|
||||||
|
233 245 157
|
||||||
|
255 230 198
|
||||||
|
222 163 139
|
||||||
|
255 195 132
|
||||||
|
255 247 160
|
||||||
|
255 247 228
|
||||||
19
data/palette/winds-seed-pc98.pal
Normal file
19
data/palette/winds-seed-pc98.pal
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
16
|
||||||
|
0 0 0
|
||||||
|
50 1 50
|
||||||
|
84 1 103
|
||||||
|
118 50 118
|
||||||
|
50 50 171
|
||||||
|
35 103 239
|
||||||
|
152 186 220
|
||||||
|
253 253 253
|
||||||
|
1 186 152
|
||||||
|
1 137 84
|
||||||
|
254 239 69
|
||||||
|
119 70 2
|
||||||
|
186 118 84
|
||||||
|
254 1 69
|
||||||
|
239 152 152
|
||||||
|
254 205 205
|
||||||
@@ -4,17 +4,7 @@ frameWidth: 8
|
|||||||
frameHeight: 16
|
frameHeight: 16
|
||||||
|
|
||||||
animations:
|
animations:
|
||||||
- name: stand
|
- name: default
|
||||||
speed: 0.1333
|
|
||||||
loop: 0
|
|
||||||
frames: [0]
|
|
||||||
|
|
||||||
- name: walk
|
|
||||||
speed: 0.1333
|
speed: 0.1333
|
||||||
loop: 0
|
loop: 0
|
||||||
frames: [0, 1, 2, 3]
|
frames: [0, 1, 2, 3]
|
||||||
|
|
||||||
- name: walk_menu
|
|
||||||
speed: 0.0
|
|
||||||
loop: 0
|
|
||||||
frames: [0, 1, 2, 3]
|
|
||||||
|
|||||||
@@ -4,17 +4,7 @@ frameWidth: 8
|
|||||||
frameHeight: 16
|
frameHeight: 16
|
||||||
|
|
||||||
animations:
|
animations:
|
||||||
- name: stand
|
- name: default
|
||||||
speed: 0.1333
|
|
||||||
loop: 0
|
|
||||||
frames: [0]
|
|
||||||
|
|
||||||
- name: walk
|
|
||||||
speed: 0.1333
|
speed: 0.1333
|
||||||
loop: 0
|
loop: 0
|
||||||
frames: [0, 1, 2, 3, 4, 5, 6, 7]
|
frames: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||||
|
|
||||||
- name: walk_menu
|
|
||||||
speed: 0.0
|
|
||||||
loop: 0
|
|
||||||
frames: [0, 1, 2, 3, 4, 5, 6, 7]
|
|
||||||
|
|||||||
@@ -92,21 +92,21 @@ namespace GlobalInputs {
|
|||||||
|
|
||||||
void handleToggleShaders() {
|
void handleToggleShaders() {
|
||||||
Screen::get()->toggleShaders();
|
Screen::get()->toggleShaders();
|
||||||
Notifier::get()->show({Locale::get()->get(Options::video.postfx ? "ui.shaders_enabled" : "ui.shaders_disabled")}); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get(Options::video.shader.enabled ? "ui.shaders_enabled" : "ui.shaders_disabled")}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNextShaderPreset() {
|
void handleNextShaderPreset() {
|
||||||
if (Options::current_shader == Rendering::ShaderType::CRTPI) {
|
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||||
if (!Options::crtpi_presets.empty()) {
|
if (!Options::crtpi_presets.empty()) {
|
||||||
Options::current_crtpi_preset = (Options::current_crtpi_preset + 1) % static_cast<int>(Options::crtpi_presets.size());
|
Options::video.shader.current_crtpi_preset = (Options::video.shader.current_crtpi_preset + 1) % static_cast<int>(Options::crtpi_presets.size());
|
||||||
Screen::get()->reloadCrtPi();
|
Screen::get()->reloadCrtPi();
|
||||||
Notifier::get()->show({Locale::get()->get("ui.crtpi") + " " + Options::crtpi_presets[static_cast<size_t>(Options::current_crtpi_preset)].name}); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get("ui.crtpi") + " " + prettyName(Options::crtpi_presets[static_cast<size_t>(Options::video.shader.current_crtpi_preset)].name)}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!Options::postfx_presets.empty()) {
|
if (!Options::postfx_presets.empty()) {
|
||||||
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
|
Options::video.shader.current_postfx_preset = (Options::video.shader.current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
|
||||||
Screen::get()->reloadPostFX();
|
Screen::get()->reloadPostFX();
|
||||||
Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name}); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + prettyName(Options::postfx_presets[static_cast<size_t>(Options::video.shader.current_postfx_preset)].name)}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,17 +114,22 @@ namespace GlobalInputs {
|
|||||||
void handleNextShader() {
|
void handleNextShader() {
|
||||||
Screen::get()->nextShader();
|
Screen::get()->nextShader();
|
||||||
Notifier::get()->show({Locale::get()->get("ui.shader") + " " + // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get("ui.shader") + " " + // NOLINT(readability-static-accessed-through-instance)
|
||||||
(Options::current_shader == Rendering::ShaderType::CRTPI ? "CRTPI" : "POSTFX")});
|
(Options::video.shader.current_shader == Rendering::ShaderType::CRTPI ? "CRTPI" : "POSTFX")});
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNextPalette() {
|
void handleNextPalette() {
|
||||||
Screen::get()->nextPalette();
|
Screen::get()->nextPalette();
|
||||||
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette}); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + toUpper(Screen::get()->getPalettePrettyName())}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
void handlePreviousPalette() {
|
void handlePreviousPalette() {
|
||||||
Screen::get()->previousPalette();
|
Screen::get()->previousPalette();
|
||||||
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette}); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + toUpper(Screen::get()->getPalettePrettyName())}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleNextPaletteSortMode() {
|
||||||
|
Screen::get()->nextPaletteSortMode();
|
||||||
|
Notifier::get()->show({Locale::get()->get("ui.palette_sort") + " " + toUpper(Screen::get()->getPaletteSortModeName())}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleToggleIntegerScale() {
|
void handleToggleIntegerScale() {
|
||||||
@@ -160,20 +165,25 @@ namespace GlobalInputs {
|
|||||||
return InputAction::WINDOW_INC_ZOOM;
|
return InputAction::WINDOW_INC_ZOOM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_SHADER, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Screen::get()->isHardwareAccelerated()) {
|
||||||
if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) {
|
if (Input::get()->checkAction(InputAction::TOGGLE_SHADER, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4
|
if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) {
|
||||||
|
return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4
|
||||||
|
}
|
||||||
|
if (Options::video.shader.enabled && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
|
||||||
|
return InputAction::NEXT_SHADER_PRESET; // Shift+F4
|
||||||
|
}
|
||||||
|
return InputAction::TOGGLE_SHADER; // F4
|
||||||
}
|
}
|
||||||
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
|
|
||||||
return InputAction::NEXT_SHADER_PRESET; // Shift+F4
|
|
||||||
}
|
|
||||||
return InputAction::TOGGLE_SHADER; // F4
|
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::NEXT_PALETTE;
|
if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) {
|
||||||
|
return InputAction::PREVIOUS_PALETTE; // Ctrl+F5
|
||||||
|
}
|
||||||
|
return InputAction::NEXT_PALETTE; // F5
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::PREVIOUS_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::NEXT_PALETTE_SORT, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::PREVIOUS_PALETTE;
|
return InputAction::NEXT_PALETTE_SORT; // F6
|
||||||
}
|
}
|
||||||
if (Input::get()->checkAction(InputAction::TOGGLE_INTEGER_SCALE, Input::DO_NOT_ALLOW_REPEAT)) {
|
if (Input::get()->checkAction(InputAction::TOGGLE_INTEGER_SCALE, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||||
return InputAction::TOGGLE_INTEGER_SCALE;
|
return InputAction::TOGGLE_INTEGER_SCALE;
|
||||||
@@ -271,6 +281,10 @@ namespace GlobalInputs {
|
|||||||
handlePreviousPalette();
|
handlePreviousPalette();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InputAction::NEXT_PALETTE_SORT:
|
||||||
|
handleNextPaletteSortMode();
|
||||||
|
break;
|
||||||
|
|
||||||
case InputAction::TOGGLE_INTEGER_SCALE:
|
case InputAction::TOGGLE_INTEGER_SCALE:
|
||||||
handleToggleIntegerScale();
|
handleToggleIntegerScale();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ Input::Input(std::string game_controller_db_path)
|
|||||||
{Action::TOGGLE_FULLSCREEN, KeyState{.scancode = SDL_SCANCODE_F3}},
|
{Action::TOGGLE_FULLSCREEN, KeyState{.scancode = SDL_SCANCODE_F3}},
|
||||||
{Action::TOGGLE_SHADER, KeyState{.scancode = SDL_SCANCODE_F4}},
|
{Action::TOGGLE_SHADER, KeyState{.scancode = SDL_SCANCODE_F4}},
|
||||||
{Action::NEXT_PALETTE, KeyState{.scancode = SDL_SCANCODE_F5}},
|
{Action::NEXT_PALETTE, KeyState{.scancode = SDL_SCANCODE_F5}},
|
||||||
{Action::PREVIOUS_PALETTE, KeyState{.scancode = SDL_SCANCODE_F6}},
|
{Action::NEXT_PALETTE_SORT, KeyState{.scancode = SDL_SCANCODE_F6}},
|
||||||
{Action::TOGGLE_INTEGER_SCALE, KeyState{.scancode = SDL_SCANCODE_F7}},
|
{Action::TOGGLE_INTEGER_SCALE, KeyState{.scancode = SDL_SCANCODE_F7}},
|
||||||
{Action::TOGGLE_IN_GAME_MUSIC, KeyState{.scancode = SDL_SCANCODE_F8}},
|
{Action::TOGGLE_IN_GAME_MUSIC, KeyState{.scancode = SDL_SCANCODE_F8}},
|
||||||
{Action::TOGGLE_BORDER, KeyState{.scancode = SDL_SCANCODE_F9}},
|
{Action::TOGGLE_BORDER, KeyState{.scancode = SDL_SCANCODE_F9}},
|
||||||
{Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F10}},
|
{Action::TOGGLE_VSYNC, KeyState{.scancode = SDL_SCANCODE_F10}},
|
||||||
{Action::PAUSE, KeyState{.scancode = SDL_SCANCODE_F11}},
|
{Action::PAUSE, KeyState{.scancode = SDL_SCANCODE_F11}},
|
||||||
{Action::TOGGLE_INFO, KeyState{.scancode = SDL_SCANCODE_F12}},
|
{Action::TOGGLE_INFO, KeyState{.scancode = SDL_SCANCODE_F12}},
|
||||||
{Action::TOGGLE_CONSOLE, KeyState{.scancode = SDL_SCANCODE_TAB}}};
|
{Action::TOGGLE_CONSOLE, KeyState{.scancode = SDL_SCANCODE_GRAVE}}};
|
||||||
|
|
||||||
initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD
|
initSDLGamePad(); // Inicializa el subsistema SDL_INIT_GAMEPAD
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const std::unordered_map<InputAction, std::string> ACTION_TO_STRING = {
|
|||||||
{InputAction::TOGGLE_IN_GAME_MUSIC, "TOGGLE_MUSIC"},
|
{InputAction::TOGGLE_IN_GAME_MUSIC, "TOGGLE_MUSIC"},
|
||||||
{InputAction::NEXT_PALETTE, "NEXT_PALETTE"},
|
{InputAction::NEXT_PALETTE, "NEXT_PALETTE"},
|
||||||
{InputAction::PREVIOUS_PALETTE, "PREVIOUS_PALETTE"},
|
{InputAction::PREVIOUS_PALETTE, "PREVIOUS_PALETTE"},
|
||||||
|
{InputAction::NEXT_PALETTE_SORT, "NEXT_PALETTE_SORT"},
|
||||||
{InputAction::TOGGLE_SHADER, "TOGGLE_POSTFX"},
|
{InputAction::TOGGLE_SHADER, "TOGGLE_POSTFX"},
|
||||||
{InputAction::NEXT_SHADER_PRESET, "NEXT_POSTFX_PRESET"},
|
{InputAction::NEXT_SHADER_PRESET, "NEXT_POSTFX_PRESET"},
|
||||||
{InputAction::TOGGLE_INFO, "TOGGLE_DEBUG"},
|
{InputAction::TOGGLE_INFO, "TOGGLE_DEBUG"},
|
||||||
@@ -42,6 +43,7 @@ const std::unordered_map<std::string, InputAction> STRING_TO_ACTION = {
|
|||||||
{"TOGGLE_MUSIC", InputAction::TOGGLE_IN_GAME_MUSIC},
|
{"TOGGLE_MUSIC", InputAction::TOGGLE_IN_GAME_MUSIC},
|
||||||
{"NEXT_PALETTE", InputAction::NEXT_PALETTE},
|
{"NEXT_PALETTE", InputAction::NEXT_PALETTE},
|
||||||
{"PREVIOUS_PALETTE", InputAction::PREVIOUS_PALETTE},
|
{"PREVIOUS_PALETTE", InputAction::PREVIOUS_PALETTE},
|
||||||
|
{"NEXT_PALETTE_SORT", InputAction::NEXT_PALETTE_SORT},
|
||||||
{"TOGGLE_POSTFX", InputAction::TOGGLE_SHADER},
|
{"TOGGLE_POSTFX", InputAction::TOGGLE_SHADER},
|
||||||
{"NEXT_POSTFX_PRESET", InputAction::NEXT_SHADER_PRESET},
|
{"NEXT_POSTFX_PRESET", InputAction::NEXT_SHADER_PRESET},
|
||||||
{"TOGGLE_DEBUG", InputAction::TOGGLE_INFO},
|
{"TOGGLE_DEBUG", InputAction::TOGGLE_INFO},
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ enum class InputAction : int { // Acciones de entrada posibles en el juego
|
|||||||
TOGGLE_IN_GAME_MUSIC,
|
TOGGLE_IN_GAME_MUSIC,
|
||||||
NEXT_PALETTE,
|
NEXT_PALETTE,
|
||||||
PREVIOUS_PALETTE,
|
PREVIOUS_PALETTE,
|
||||||
|
NEXT_PALETTE_SORT,
|
||||||
TOGGLE_INFO,
|
TOGGLE_INFO,
|
||||||
TOGGLE_CONSOLE,
|
TOGGLE_CONSOLE,
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||||
@@ -15,6 +16,12 @@ void Locale::init(const std::string& file_path) { // NOLINT(readability-convert
|
|||||||
Locale::instance->loadFromFile(file_path);
|
Locale::instance->loadFromFile(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [SINGLETON] Crea el objeto desde contenido en memoria (para release con pack)
|
||||||
|
void Locale::initFromContent(const std::string& content) { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
Locale::instance = new Locale();
|
||||||
|
Locale::instance->loadFromContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
// [SINGLETON] Destruye el objeto con esta función estática
|
// [SINGLETON] Destruye el objeto con esta función estática
|
||||||
void Locale::destroy() {
|
void Locale::destroy() {
|
||||||
delete Locale::instance;
|
delete Locale::instance;
|
||||||
@@ -55,6 +62,24 @@ void Locale::flatten(const void* node_ptr, const std::string& prefix) { // NOLI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Carga las traducciones desde contenido YAML en memoria
|
||||||
|
void Locale::loadFromContent(const std::string& content) { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
if (content.empty()) {
|
||||||
|
std::cerr << "Locale: contenido vacío, sin traducciones cargadas\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::istringstream stream(content);
|
||||||
|
auto yaml = fkyaml::node::deserialize(stream);
|
||||||
|
flatten(&yaml, "");
|
||||||
|
|
||||||
|
std::cout << "Locale: " << strings_.size() << " traducciones cargadas desde pack\n";
|
||||||
|
} catch (const fkyaml::exception& e) {
|
||||||
|
std::cerr << "Locale: error al parsear YAML: " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Carga las traducciones desde el fichero YAML indicado
|
// Carga las traducciones desde el fichero YAML indicado
|
||||||
void Locale::loadFromFile(const std::string& file_path) { // NOLINT(readability-convert-member-functions-to-static)
|
void Locale::loadFromFile(const std::string& file_path) { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
if (file_path.empty()) {
|
if (file_path.empty()) {
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
// No se permite cambio de idioma en caliente.
|
// No se permite cambio de idioma en caliente.
|
||||||
class Locale {
|
class Locale {
|
||||||
public:
|
public:
|
||||||
static void init(const std::string& file_path); // Crea e inicializa el singleton
|
static void init(const std::string& file_path); // Crea e inicializa el singleton
|
||||||
static void destroy(); // Destruye el singleton
|
static void initFromContent(const std::string& content); // Crea e inicializa desde contenido en memoria (pack)
|
||||||
static auto get() -> Locale*; // Devuelve el singleton
|
static void destroy(); // Destruye el singleton
|
||||||
|
static auto get() -> Locale*; // Devuelve el singleton
|
||||||
|
|
||||||
// Devuelve la traducción de la clave dada.
|
// Devuelve la traducción de la clave dada.
|
||||||
// Si la clave no existe, devuelve la propia clave como fallback.
|
// Si la clave no existe, devuelve la propia clave como fallback.
|
||||||
@@ -19,6 +20,7 @@ class Locale {
|
|||||||
private:
|
private:
|
||||||
Locale() = default;
|
Locale() = default;
|
||||||
void loadFromFile(const std::string& file_path);
|
void loadFromFile(const std::string& file_path);
|
||||||
|
void loadFromContent(const std::string& content);
|
||||||
void flatten(const void* node_ptr, const std::string& prefix); // Aplana nodos YAML anidados
|
void flatten(const void* node_ptr, const std::string& prefix); // Aplana nodos YAML anidados
|
||||||
|
|
||||||
static Locale* instance;
|
static Locale* instance;
|
||||||
|
|||||||
276
source/core/rendering/palette_manager.cpp
Normal file
276
source/core/rendering/palette_manager.cpp
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
#include "core/rendering/palette_manager.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <cmath>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core/rendering/surface.hpp"
|
||||||
|
#include "core/resources/resource_cache.hpp"
|
||||||
|
#include "game/defaults.hpp"
|
||||||
|
#include "game/options.hpp"
|
||||||
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
|
// ── Conversión string ↔ PaletteSortMode ──────────────────────────────────────
|
||||||
|
|
||||||
|
auto sortModeFromString(const std::string& str) -> PaletteSortMode {
|
||||||
|
const std::string lower = toLower(str);
|
||||||
|
if (lower == "luminance") { return PaletteSortMode::LUMINANCE; }
|
||||||
|
if (lower == "spectrum") { return PaletteSortMode::SPECTRUM; }
|
||||||
|
return PaletteSortMode::ORIGINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sortModeToString(PaletteSortMode mode) -> std::string {
|
||||||
|
switch (mode) {
|
||||||
|
case PaletteSortMode::LUMINANCE:
|
||||||
|
return "luminance";
|
||||||
|
case PaletteSortMode::SPECTRUM:
|
||||||
|
return "spectrum";
|
||||||
|
default:
|
||||||
|
return "original";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Paleta de referencia ZX Spectrum (16 colores ARGB) ───────────────────────
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Helpers para extraer componentes RGB de un color ARGB (0xAARRGGBB)
|
||||||
|
constexpr auto redOf(Uint32 c) -> int { return static_cast<int>((c >> 16) & 0xFF); }
|
||||||
|
constexpr auto greenOf(Uint32 c) -> int { return static_cast<int>((c >> 8) & 0xFF); }
|
||||||
|
constexpr auto blueOf(Uint32 c) -> int { return static_cast<int>(c & 0xFF); }
|
||||||
|
|
||||||
|
constexpr auto makeARGB(int r, int g, int b) -> Uint32 {
|
||||||
|
return (0xFFU << 24) | (static_cast<Uint32>(r) << 16) | (static_cast<Uint32>(g) << 8) | static_cast<Uint32>(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paleta ZX Spectrum de referencia (misma que en tools/sort_palette/sort_palette.py)
|
||||||
|
constexpr std::array<Uint32, 16> SPECTRUM_REFERENCE = {
|
||||||
|
makeARGB(0, 0, 0),
|
||||||
|
makeARGB(0, 0, 0),
|
||||||
|
makeARGB(0, 0, 216),
|
||||||
|
makeARGB(0, 0, 255),
|
||||||
|
makeARGB(216, 0, 0),
|
||||||
|
makeARGB(255, 0, 0),
|
||||||
|
makeARGB(216, 0, 216),
|
||||||
|
makeARGB(255, 0, 255),
|
||||||
|
makeARGB(0, 216, 0),
|
||||||
|
makeARGB(0, 255, 0),
|
||||||
|
makeARGB(0, 216, 216),
|
||||||
|
makeARGB(0, 255, 255),
|
||||||
|
makeARGB(216, 216, 0),
|
||||||
|
makeARGB(255, 255, 0),
|
||||||
|
makeARGB(216, 216, 216),
|
||||||
|
makeARGB(255, 255, 255),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Luminancia percibida (ITU-R BT.709)
|
||||||
|
auto luminance(Uint32 color) -> double {
|
||||||
|
return 0.2126 * redOf(color) + 0.7152 * greenOf(color) + 0.0722 * blueOf(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distancia euclídea al cuadrado en espacio RGB (no necesita sqrt para comparar)
|
||||||
|
auto rgbDistanceSq(Uint32 a, Uint32 b) -> int {
|
||||||
|
const int dr = redOf(a) - redOf(b);
|
||||||
|
const int dg = greenOf(a) - greenOf(b);
|
||||||
|
const int db = blueOf(a) - blueOf(b);
|
||||||
|
return dr * dr + dg * dg + db * db;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cuenta los colores activos en la paleta (los que tienen alpha != 0)
|
||||||
|
auto countActiveColors(const Palette& palette) -> size_t {
|
||||||
|
size_t count = 0;
|
||||||
|
for (const auto& c : palette) {
|
||||||
|
if (c == 0) { break; }
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordenar por luminancia
|
||||||
|
auto sortByLuminance(const Palette& palette) -> Palette {
|
||||||
|
const size_t n = countActiveColors(palette);
|
||||||
|
std::vector<Uint32> colors(palette.begin(), palette.begin() + static_cast<ptrdiff_t>(n));
|
||||||
|
std::sort(colors.begin(), colors.end(), [](Uint32 a, Uint32 b) {
|
||||||
|
return luminance(a) < luminance(b);
|
||||||
|
});
|
||||||
|
|
||||||
|
Palette result{};
|
||||||
|
result.fill(0);
|
||||||
|
std::copy(colors.begin(), colors.end(), result.begin());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordenar por similitud con la paleta ZX Spectrum (greedy matching)
|
||||||
|
auto sortBySpectrum(const Palette& palette) -> Palette {
|
||||||
|
const size_t n = countActiveColors(palette);
|
||||||
|
std::vector<Uint32> available(palette.begin(), palette.begin() + static_cast<ptrdiff_t>(n));
|
||||||
|
std::vector<Uint32> result;
|
||||||
|
result.reserve(n);
|
||||||
|
|
||||||
|
// Para cada color de referencia del Spectrum, buscar el más cercano disponible
|
||||||
|
const size_t refs = std::min(n, SPECTRUM_REFERENCE.size());
|
||||||
|
for (size_t i = 0; i < refs && !available.empty(); ++i) {
|
||||||
|
const Uint32 ref = SPECTRUM_REFERENCE[i];
|
||||||
|
auto best = std::min_element(available.begin(), available.end(), [ref](Uint32 a, Uint32 b) {
|
||||||
|
return rgbDistanceSq(a, ref) < rgbDistanceSq(b, ref);
|
||||||
|
});
|
||||||
|
result.push_back(*best);
|
||||||
|
available.erase(best);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si quedan colores sin asignar, añadirlos al final
|
||||||
|
for (const auto& c : available) {
|
||||||
|
result.push_back(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Palette out{};
|
||||||
|
out.fill(0);
|
||||||
|
std::copy(result.begin(), result.end(), out.begin());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// ── PaletteManager ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
PaletteManager::PaletteManager(
|
||||||
|
std::vector<std::string> raw_paths,
|
||||||
|
const std::string& initial_name,
|
||||||
|
PaletteSortMode initial_sort_mode,
|
||||||
|
std::shared_ptr<Surface> game_surface,
|
||||||
|
std::shared_ptr<Surface> border_surface,
|
||||||
|
OnChangeCallback on_change)
|
||||||
|
: palettes_(std::move(raw_paths)),
|
||||||
|
sort_mode_(initial_sort_mode),
|
||||||
|
game_surface_(std::move(game_surface)),
|
||||||
|
border_surface_(std::move(border_surface)),
|
||||||
|
on_change_(std::move(on_change)) {
|
||||||
|
current_ = findIndex(initial_name);
|
||||||
|
|
||||||
|
// Leer y aplicar paleta inicial directamente desde el archivo
|
||||||
|
// (Resource::Cache aún no está disponible en este punto del ciclo de vida)
|
||||||
|
const auto initial_palette = sortPalette(readPalFile(palettes_.at(current_)), sort_mode_);
|
||||||
|
game_surface_->setPalette(initial_palette);
|
||||||
|
border_surface_->setPalette(initial_palette);
|
||||||
|
|
||||||
|
// Procesar la lista: conservar solo los nombres de archivo (sin ruta)
|
||||||
|
processPathList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteManager::next() {
|
||||||
|
if (++current_ == palettes_.size()) {
|
||||||
|
current_ = 0;
|
||||||
|
}
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteManager::previous() {
|
||||||
|
current_ = (current_ > 0) ? current_ - 1 : palettes_.size() - 1;
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::setByName(const std::string& name) -> bool {
|
||||||
|
const std::string lower_name = toLower(name + ".pal");
|
||||||
|
for (size_t i = 0; i < palettes_.size(); ++i) {
|
||||||
|
if (toLower(palettes_[i]) == lower_name) {
|
||||||
|
current_ = i;
|
||||||
|
apply();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::getNames() const -> std::vector<std::string> {
|
||||||
|
std::vector<std::string> names;
|
||||||
|
names.reserve(palettes_.size());
|
||||||
|
for (const auto& p : palettes_) {
|
||||||
|
std::string name = p;
|
||||||
|
const size_t pos = name.find(".pal");
|
||||||
|
if (pos != std::string::npos) { name.erase(pos, 4); }
|
||||||
|
std::ranges::transform(name, name.begin(), ::tolower);
|
||||||
|
names.push_back(std::move(name));
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::getCurrentName() const -> std::string {
|
||||||
|
std::string name = palettes_.at(current_);
|
||||||
|
const size_t pos = name.find(".pal");
|
||||||
|
if (pos != std::string::npos) { name.erase(pos, 4); }
|
||||||
|
std::ranges::transform(name, name.begin(), ::tolower);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::getPrettyName() const -> std::string {
|
||||||
|
std::string name = getCurrentName();
|
||||||
|
std::ranges::replace(name, '-', ' ');
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteManager::nextSortMode() {
|
||||||
|
sort_mode_ = static_cast<PaletteSortMode>((static_cast<int>(sort_mode_) + 1) % static_cast<int>(PaletteSortMode::COUNT));
|
||||||
|
Options::video.palette_sort = sortModeToString(sort_mode_);
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteManager::setSortMode(PaletteSortMode mode) {
|
||||||
|
sort_mode_ = mode;
|
||||||
|
Options::video.palette_sort = sortModeToString(sort_mode_);
|
||||||
|
apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::getSortMode() const -> PaletteSortMode {
|
||||||
|
return sort_mode_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::getSortModeName() const -> std::string {
|
||||||
|
return sortModeToString(sort_mode_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteManager::apply() {
|
||||||
|
Palette raw = Resource::Cache::get()->getPalette(palettes_.at(current_));
|
||||||
|
Palette sorted = sortPalette(raw, sort_mode_);
|
||||||
|
game_surface_->loadPalette(sorted);
|
||||||
|
border_surface_->loadPalette(sorted);
|
||||||
|
|
||||||
|
Options::video.palette = getCurrentName();
|
||||||
|
|
||||||
|
if (on_change_) {
|
||||||
|
on_change_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::findIndex(const std::string& name) const -> size_t {
|
||||||
|
const std::string lower_name = toLower(name + ".pal");
|
||||||
|
for (size_t i = 0; i < palettes_.size(); ++i) {
|
||||||
|
if (toLower(getFileName(palettes_[i])) == lower_name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback: buscar la paleta por defecto
|
||||||
|
const std::string default_name = toLower(std::string(Defaults::Video::PALETTE_NAME) + ".pal");
|
||||||
|
for (size_t i = 0; i < palettes_.size(); ++i) {
|
||||||
|
if (toLower(getFileName(palettes_[i])) == default_name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteManager::processPathList() {
|
||||||
|
for (auto& palette : palettes_) {
|
||||||
|
palette = getFileName(palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PaletteManager::sortPalette(const Palette& palette, PaletteSortMode mode) -> Palette {
|
||||||
|
switch (mode) {
|
||||||
|
case PaletteSortMode::LUMINANCE:
|
||||||
|
return sortByLuminance(palette);
|
||||||
|
case PaletteSortMode::SPECTRUM:
|
||||||
|
return sortBySpectrum(palette);
|
||||||
|
default:
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
}
|
||||||
64
source/core/rendering/palette_manager.hpp
Normal file
64
source/core/rendering/palette_manager.hpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Alias de paleta (igual que en surface.hpp; evita incluir todo el header)
|
||||||
|
using Palette = std::array<Uint32, 256>;
|
||||||
|
|
||||||
|
class Surface;
|
||||||
|
|
||||||
|
// Modo de ordenación de paletas
|
||||||
|
enum class PaletteSortMode : int {
|
||||||
|
ORIGINAL = 0, // Paleta tal cual viene del fichero
|
||||||
|
LUMINANCE = 1, // Ordenada por luminancia percibida
|
||||||
|
SPECTRUM = 2, // Reordenada para imitar la paleta ZX Spectrum
|
||||||
|
COUNT = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// Conversión string ↔ PaletteSortMode
|
||||||
|
auto sortModeFromString(const std::string& str) -> PaletteSortMode;
|
||||||
|
auto sortModeToString(PaletteSortMode mode) -> std::string;
|
||||||
|
|
||||||
|
class PaletteManager {
|
||||||
|
public:
|
||||||
|
using OnChangeCallback = std::function<void()>;
|
||||||
|
|
||||||
|
PaletteManager(
|
||||||
|
std::vector<std::string> raw_paths,
|
||||||
|
const std::string& initial_name,
|
||||||
|
PaletteSortMode initial_sort_mode,
|
||||||
|
std::shared_ptr<Surface> game_surface,
|
||||||
|
std::shared_ptr<Surface> border_surface,
|
||||||
|
OnChangeCallback on_change = nullptr);
|
||||||
|
|
||||||
|
void next(); // Avanza a la siguiente paleta
|
||||||
|
void previous(); // Retrocede a la paleta anterior
|
||||||
|
auto setByName(const std::string& name) -> bool; // Cambia a paleta por nombre; false si no existe
|
||||||
|
[[nodiscard]] auto getNames() const -> std::vector<std::string>; // Nombres disponibles (minúsculas, sin .pal)
|
||||||
|
[[nodiscard]] auto getCurrentName() const -> std::string; // Nombre de la paleta actual (minúsculas, sin .pal)
|
||||||
|
[[nodiscard]] auto getPrettyName() const -> std::string; // Nombre actual con guiones sustituidos por espacios
|
||||||
|
|
||||||
|
void nextSortMode(); // Cicla al siguiente modo de ordenación
|
||||||
|
void setSortMode(PaletteSortMode mode); // Establece un modo de ordenación concreto
|
||||||
|
[[nodiscard]] auto getSortMode() const -> PaletteSortMode; // Devuelve el modo de ordenación actual
|
||||||
|
[[nodiscard]] auto getSortModeName() const -> std::string; // Nombre del modo actual ("ORIGINAL", etc.)
|
||||||
|
|
||||||
|
private:
|
||||||
|
void apply(); // Aplica la paleta actual a ambas surfaces
|
||||||
|
[[nodiscard]] auto findIndex(const std::string& name) const -> size_t; // Localiza paleta por nombre en el vector
|
||||||
|
void processPathList(); // Extrae nombres de archivo de las rutas completas
|
||||||
|
static auto sortPalette(const Palette& palette, PaletteSortMode mode) -> Palette; // Reordena una paleta según el modo
|
||||||
|
|
||||||
|
std::vector<std::string> palettes_;
|
||||||
|
size_t current_{0};
|
||||||
|
PaletteSortMode sort_mode_{PaletteSortMode::ORIGINAL};
|
||||||
|
std::shared_ptr<Surface> game_surface_;
|
||||||
|
std::shared_ptr<Surface> border_surface_;
|
||||||
|
OnChangeCallback on_change_;
|
||||||
|
};
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "game/options.hpp" // Para Options
|
#include "game/options.hpp" // Para Options
|
||||||
#include "game/ui/console.hpp" // Para Console
|
#include "game/ui/console.hpp" // Para Console
|
||||||
#include "game/ui/notifier.hpp" // Para Notifier
|
#include "game/ui/notifier.hpp" // Para Notifier
|
||||||
|
#include "utils/utils.hpp" // Para prettyName
|
||||||
|
|
||||||
// [SINGLETON]
|
// [SINGLETON]
|
||||||
RenderInfo* RenderInfo::render_info = nullptr;
|
RenderInfo* RenderInfo::render_info = nullptr;
|
||||||
@@ -89,20 +90,20 @@ void RenderInfo::render() const {
|
|||||||
line += " | " + zoom_str + "x";
|
line += " | " + zoom_str + "x";
|
||||||
|
|
||||||
// PostFX: muestra shader + preset y supersampling, o nada si está desactivado
|
// PostFX: muestra shader + preset y supersampling, o nada si está desactivado
|
||||||
if (Options::video.postfx) {
|
if (Options::video.shader.enabled) {
|
||||||
const bool IS_CRTPI = (Options::current_shader == Rendering::ShaderType::CRTPI);
|
const bool IS_CRTPI = (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI);
|
||||||
const std::string SHADER_NAME = IS_CRTPI ? "crtpi" : "postfx";
|
const std::string SHADER_NAME = IS_CRTPI ? "crtpi" : "postfx";
|
||||||
std::string preset_name = "-";
|
std::string preset_name = "-";
|
||||||
if (IS_CRTPI) {
|
if (IS_CRTPI) {
|
||||||
if (!Options::crtpi_presets.empty()) {
|
if (!Options::crtpi_presets.empty()) {
|
||||||
preset_name = Options::crtpi_presets[static_cast<size_t>(Options::current_crtpi_preset)].name;
|
preset_name = prettyName(Options::crtpi_presets[static_cast<size_t>(Options::video.shader.current_crtpi_preset)].name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!Options::postfx_presets.empty()) {
|
if (!Options::postfx_presets.empty()) {
|
||||||
preset_name = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name;
|
preset_name = prettyName(Options::postfx_presets[static_cast<size_t>(Options::video.shader.current_postfx_preset)].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const bool SHOW_SS = Options::video.supersampling && !IS_CRTPI;
|
const bool SHOW_SS = Options::video.supersampling.enabled && !IS_CRTPI;
|
||||||
line += " | " + SHADER_NAME + " " + preset_name + (SHOW_SS ? " (ss)" : "");
|
line += " | " + SHADER_NAME + " " + preset_name + (SHOW_SS ? " (ss)" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ auto Screen::get() -> Screen* {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Screen::Screen()
|
Screen::Screen() {
|
||||||
: palettes_(Resource::List::get()->getListByType(Resource::List::Type::PALETTE)) {
|
|
||||||
// Arranca SDL VIDEO, crea la ventana y el renderizador
|
// Arranca SDL VIDEO, crea la ventana y el renderizador
|
||||||
initSDLVideo();
|
initSDLVideo();
|
||||||
if (Options::video.fullscreen) { SDL_HideCursor(); }
|
if (Options::video.fullscreen) { SDL_HideCursor(); }
|
||||||
@@ -55,7 +54,6 @@ Screen::Screen()
|
|||||||
|
|
||||||
// Ajusta los tamaños
|
// Ajusta los tamaños
|
||||||
game_surface_dstrect_ = {.x = Options::video.border.width, .y = Options::video.border.height, .w = Options::game.width, .h = Options::game.height};
|
game_surface_dstrect_ = {.x = Options::video.border.width, .y = Options::video.border.height, .w = Options::game.width, .h = Options::game.height};
|
||||||
current_palette_ = findPalette(Options::video.palette);
|
|
||||||
|
|
||||||
// Define el color del borde para el modo de pantalla completa
|
// Define el color del borde para el modo de pantalla completa
|
||||||
border_color_ = static_cast<Uint8>(PaletteColor::BLACK);
|
border_color_ = static_cast<Uint8>(PaletteColor::BLACK);
|
||||||
@@ -76,19 +74,28 @@ Screen::Screen()
|
|||||||
}
|
}
|
||||||
SDL_SetTextureScaleMode(border_texture_, SDL_SCALEMODE_NEAREST);
|
SDL_SetTextureScaleMode(border_texture_, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
// Cargar la paleta una sola vez
|
// Crea las surfaces (PaletteManager aplicará la paleta inicial en su constructor)
|
||||||
auto initial_palette = readPalFile(palettes_.at(current_palette_));
|
|
||||||
|
|
||||||
// Crea la surface donde se dibujan los graficos del juego
|
|
||||||
game_surface_ = std::make_shared<Surface>(Options::game.width, Options::game.height);
|
game_surface_ = std::make_shared<Surface>(Options::game.width, Options::game.height);
|
||||||
game_surface_->setPalette(initial_palette);
|
|
||||||
game_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
game_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||||
|
|
||||||
// Crea la surface para el borde de colores
|
|
||||||
border_surface_ = std::make_shared<Surface>(Options::game.width + (Options::video.border.width * 2), Options::game.height + (Options::video.border.height * 2));
|
border_surface_ = std::make_shared<Surface>(Options::game.width + (Options::video.border.width * 2), Options::game.height + (Options::video.border.height * 2));
|
||||||
border_surface_->setPalette(initial_palette);
|
|
||||||
border_surface_->clear(border_color_);
|
border_surface_->clear(border_color_);
|
||||||
|
|
||||||
|
// Crea el gestor de paletas; aplica la paleta inicial a ambas surfaces
|
||||||
|
palette_manager_ = std::make_unique<PaletteManager>(
|
||||||
|
Resource::List::get()->getListByType(Resource::List::Type::PALETTE),
|
||||||
|
Options::video.palette,
|
||||||
|
sortModeFromString(Options::video.palette_sort),
|
||||||
|
game_surface_,
|
||||||
|
border_surface_,
|
||||||
|
[this]() {
|
||||||
|
// Actualizar caché ARGB del borde cuando cambia la paleta
|
||||||
|
if (border_is_solid_) {
|
||||||
|
border_surface_->toARGBBuffer(border_pixel_buffer_.data());
|
||||||
|
border_argb_color_ = border_pixel_buffer_[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Cachear el color ARGB inicial del borde (borde sólido por defecto)
|
// Cachear el color ARGB inicial del borde (borde sólido por defecto)
|
||||||
border_surface_->toARGBBuffer(border_pixel_buffer_.data());
|
border_surface_->toARGBBuffer(border_pixel_buffer_.data());
|
||||||
border_argb_color_ = border_pixel_buffer_[0];
|
border_argb_color_ = border_pixel_buffer_[0];
|
||||||
@@ -99,9 +106,6 @@ Screen::Screen()
|
|||||||
// Crea el objeto de texto para la pantalla de carga
|
// Crea el objeto de texto para la pantalla de carga
|
||||||
createText();
|
createText();
|
||||||
|
|
||||||
// Extrae el nombre de las paletas desde su ruta
|
|
||||||
processPaletteList();
|
|
||||||
|
|
||||||
// Renderizar una vez la textura vacía para que tenga contenido válido
|
// Renderizar una vez la textura vacía para que tenga contenido válido
|
||||||
// antes de inicializar los shaders (evita pantalla negra)
|
// antes de inicializar los shaders (evita pantalla negra)
|
||||||
SDL_RenderTexture(renderer_, game_texture_, nullptr, nullptr);
|
SDL_RenderTexture(renderer_, game_texture_, nullptr, nullptr);
|
||||||
@@ -194,6 +198,21 @@ auto Screen::incWindowZoom() -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Establece el zoom directamente; false si fuera del rango [1, max_zoom] o en pantalla completa
|
||||||
|
auto Screen::setWindowZoom(int zoom) -> bool {
|
||||||
|
if (Options::video.fullscreen) { return false; }
|
||||||
|
if (zoom < 1 || zoom > Options::window.max_zoom) { return false; }
|
||||||
|
if (zoom == Options::window.zoom) { return false; }
|
||||||
|
Options::window.zoom = zoom;
|
||||||
|
setVideoMode(Options::video.fullscreen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Devuelve el zoom máximo permitido según la pantalla actual
|
||||||
|
auto Screen::getMaxZoom() const -> int {
|
||||||
|
return Options::window.max_zoom;
|
||||||
|
}
|
||||||
|
|
||||||
// Cambia el color del borde
|
// Cambia el color del borde
|
||||||
void Screen::setBorderColor(Uint8 color) {
|
void Screen::setBorderColor(Uint8 color) {
|
||||||
border_color_ = color;
|
border_color_ = color;
|
||||||
@@ -221,11 +240,11 @@ void Screen::renderNotifications() const {
|
|||||||
|
|
||||||
// Activa/desactiva todos los shaders respetando el shader actualmente seleccionado
|
// Activa/desactiva todos los shaders respetando el shader actualmente seleccionado
|
||||||
void Screen::toggleShaders() {
|
void Screen::toggleShaders() {
|
||||||
Options::video.postfx = !Options::video.postfx;
|
Options::video.shader.enabled = !Options::video.shader.enabled;
|
||||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||||
if (Options::video.postfx) {
|
if (Options::video.shader.enabled) {
|
||||||
// Activar: usar el shader actualmente seleccionado
|
// Activar: usar el shader actualmente seleccionado
|
||||||
if (Options::current_shader == Rendering::ShaderType::CRTPI) {
|
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||||
shader_backend_->setActiveShader(Rendering::ShaderType::CRTPI);
|
shader_backend_->setActiveShader(Rendering::ShaderType::CRTPI);
|
||||||
applyCurrentCrtPiPreset();
|
applyCurrentCrtPiPreset();
|
||||||
} else {
|
} else {
|
||||||
@@ -244,10 +263,10 @@ void Screen::toggleShaders() {
|
|||||||
|
|
||||||
// Recarga el shader del preset actual sin toggle
|
// Recarga el shader del preset actual sin toggle
|
||||||
void Screen::reloadPostFX() {
|
void Screen::reloadPostFX() {
|
||||||
if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
if (Options::video.shader.enabled && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||||
// El backend ya está activo: solo actualizar uniforms, sin recrear el pipeline
|
// El backend ya está activo: solo actualizar uniforms, sin recrear el pipeline
|
||||||
applyCurrentPostFXPreset();
|
applyCurrentPostFXPreset();
|
||||||
} else if (Options::video.postfx) {
|
} else if (Options::video.shader.enabled) {
|
||||||
initShaders();
|
initShaders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,55 +361,10 @@ void Screen::setRendererSurface(const std::shared_ptr<Surface>& surface) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cambia la paleta
|
// Cambia la paleta
|
||||||
void Screen::nextPalette() {
|
void Screen::nextPalette() { palette_manager_->next(); }
|
||||||
++current_palette_;
|
|
||||||
if (current_palette_ == static_cast<int>(palettes_.size())) {
|
|
||||||
current_palette_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPalete();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cambia la paleta
|
// Cambia la paleta
|
||||||
void Screen::previousPalette() {
|
void Screen::previousPalette() { palette_manager_->previous(); }
|
||||||
if (current_palette_ > 0) {
|
|
||||||
--current_palette_;
|
|
||||||
} else {
|
|
||||||
current_palette_ = static_cast<Uint8>(palettes_.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
setPalete();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establece la paleta
|
|
||||||
void Screen::setPalete() { // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
game_surface_->loadPalette(Resource::Cache::get()->getPalette(palettes_.at(current_palette_)));
|
|
||||||
border_surface_->loadPalette(Resource::Cache::get()->getPalette(palettes_.at(current_palette_)));
|
|
||||||
|
|
||||||
Options::video.palette = palettes_.at(current_palette_);
|
|
||||||
|
|
||||||
// Eliminar ".gif"
|
|
||||||
size_t pos = Options::video.palette.find(".pal");
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
Options::video.palette.erase(pos, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convertir a mayúsculas
|
|
||||||
std::ranges::transform(Options::video.palette, Options::video.palette.begin(), ::toupper);
|
|
||||||
|
|
||||||
// Actualizar caché si el borde es sólido (la paleta cambia el valor ARGB del color)
|
|
||||||
if (border_is_solid_) {
|
|
||||||
border_surface_->toARGBBuffer(border_pixel_buffer_.data());
|
|
||||||
border_argb_color_ = border_pixel_buffer_[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extrae los nombres de las paletas
|
|
||||||
void Screen::processPaletteList() {
|
|
||||||
for (auto& palette : palettes_) {
|
|
||||||
palette = getFileName(palette);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copia la surface a la textura
|
// Copia la surface a la textura
|
||||||
void Screen::surfaceToTexture() { // NOLINT(readability-convert-member-functions-to-static)
|
void Screen::surfaceToTexture() { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
@@ -470,17 +444,15 @@ void Screen::renderOverlays() {
|
|||||||
if (Console::get() != nullptr) { Console::get()->render(); } // Console (encima)
|
if (Console::get() != nullptr) { Console::get()->render(); } // Console (encima)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Localiza la paleta dentro del vector de paletas
|
// Cambia a una paleta por nombre (case-insensitive); devuelve false si no existe
|
||||||
auto Screen::findPalette(const std::string& name) -> size_t { // NOLINT(readability-convert-member-functions-to-static)
|
auto Screen::setPaletteByName(const std::string& name) -> bool { return palette_manager_->setByName(name); }
|
||||||
std::string upper_name = toUpper(name + ".pal");
|
|
||||||
|
|
||||||
for (size_t i = 0; i < palettes_.size(); ++i) {
|
// Devuelve los nombres de paletas disponibles (minúsculas, sin extensión .pal)
|
||||||
if (toUpper(getFileName(palettes_[i])) == upper_name) {
|
auto Screen::getPaletteNames() const -> std::vector<std::string> { return palette_manager_->getNames(); }
|
||||||
return i;
|
auto Screen::getPalettePrettyName() const -> std::string { return palette_manager_->getPrettyName(); }
|
||||||
}
|
void Screen::nextPaletteSortMode() { palette_manager_->nextSortMode(); }
|
||||||
}
|
void Screen::setPaletteSortMode(PaletteSortMode mode) { palette_manager_->setSortMode(mode); }
|
||||||
return static_cast<size_t>(0);
|
auto Screen::getPaletteSortModeName() const -> std::string { return palette_manager_->getSortModeName(); }
|
||||||
}
|
|
||||||
|
|
||||||
// Limpia la game_surface_
|
// Limpia la game_surface_
|
||||||
void Screen::clearSurface(Uint8 index) { game_surface_->clear(index); }
|
void Screen::clearSurface(Uint8 index) { game_surface_->clear(index); }
|
||||||
@@ -537,14 +509,14 @@ auto loadData(const std::string& filepath) -> std::vector<uint8_t> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Screen::setLinearUpscale(bool linear) {
|
void Screen::setLinearUpscale(bool linear) {
|
||||||
Options::video.linear_upscale = linear;
|
Options::video.supersampling.linear_upscale = linear;
|
||||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||||
shader_backend_->setLinearUpscale(linear);
|
shader_backend_->setLinearUpscale(linear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::setDownscaleAlgo(int algo) {
|
void Screen::setDownscaleAlgo(int algo) {
|
||||||
Options::video.downscale_algo = algo;
|
Options::video.supersampling.downscale_algo = algo;
|
||||||
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
if (shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||||
shader_backend_->setDownscaleAlgo(algo);
|
shader_backend_->setDownscaleAlgo(algo);
|
||||||
}
|
}
|
||||||
@@ -557,8 +529,8 @@ auto Screen::getSsTextureSize() const -> std::pair<int, int> {
|
|||||||
|
|
||||||
// Activa/desactiva el supersampling global (Ctrl+F4)
|
// Activa/desactiva el supersampling global (Ctrl+F4)
|
||||||
void Screen::toggleSupersampling() {
|
void Screen::toggleSupersampling() {
|
||||||
Options::video.supersampling = !Options::video.supersampling;
|
Options::video.supersampling.enabled = !Options::video.supersampling.enabled;
|
||||||
if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
if (Options::video.shader.enabled && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||||
applyCurrentPostFXPreset();
|
applyCurrentPostFXPreset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,11 +538,11 @@ void Screen::toggleSupersampling() {
|
|||||||
// Aplica los parámetros del preset actual al backend de shaders
|
// Aplica los parámetros del preset actual al backend de shaders
|
||||||
void Screen::applyCurrentPostFXPreset() { // NOLINT(readability-convert-member-functions-to-static)
|
void Screen::applyCurrentPostFXPreset() { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
if (shader_backend_ && !Options::postfx_presets.empty()) {
|
if (shader_backend_ && !Options::postfx_presets.empty()) {
|
||||||
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)];
|
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::video.shader.current_postfx_preset)];
|
||||||
// Supersampling es un toggle global (Options::video.supersampling), no por preset.
|
// Supersampling es un toggle global (Options::video.supersampling.enabled), no por preset.
|
||||||
// setOversample primero: puede recrear texturas antes de que setPostFXParams
|
// setOversample primero: puede recrear texturas antes de que setPostFXParams
|
||||||
// decida si hornear scanlines en CPU o aplicarlas en GPU.
|
// decida si hornear scanlines en CPU o aplicarlas en GPU.
|
||||||
shader_backend_->setOversample(Options::video.supersampling ? 3 : 1);
|
shader_backend_->setOversample(Options::video.supersampling.enabled ? 3 : 1);
|
||||||
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding, .flicker = p.flicker};
|
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding, .flicker = p.flicker};
|
||||||
shader_backend_->setPostFXParams(params);
|
shader_backend_->setPostFXParams(params);
|
||||||
}
|
}
|
||||||
@@ -579,7 +551,7 @@ void Screen::applyCurrentPostFXPreset() { // NOLINT(readability-convert-member-
|
|||||||
// Aplica los parámetros del preset CrtPi actual al backend de shaders
|
// Aplica los parámetros del preset CrtPi actual al backend de shaders
|
||||||
void Screen::applyCurrentCrtPiPreset() { // NOLINT(readability-convert-member-functions-to-static)
|
void Screen::applyCurrentCrtPiPreset() { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
if (shader_backend_ && !Options::crtpi_presets.empty()) {
|
if (shader_backend_ && !Options::crtpi_presets.empty()) {
|
||||||
const auto& p = Options::crtpi_presets[static_cast<size_t>(Options::current_crtpi_preset)];
|
const auto& p = Options::crtpi_presets[static_cast<size_t>(Options::video.shader.current_crtpi_preset)];
|
||||||
Rendering::CrtPiParams params{
|
Rendering::CrtPiParams params{
|
||||||
.scanline_weight = p.scanline_weight,
|
.scanline_weight = p.scanline_weight,
|
||||||
.scanline_gap_brightness = p.scanline_gap_brightness,
|
.scanline_gap_brightness = p.scanline_gap_brightness,
|
||||||
@@ -602,9 +574,9 @@ void Screen::applyCurrentCrtPiPreset() { // NOLINT(readability-convert-member-f
|
|||||||
|
|
||||||
// Cambia el shader de post-procesado activo y aplica el preset correspondiente
|
// Cambia el shader de post-procesado activo y aplica el preset correspondiente
|
||||||
void Screen::setActiveShader(Rendering::ShaderType type) {
|
void Screen::setActiveShader(Rendering::ShaderType type) {
|
||||||
Options::current_shader = type;
|
Options::video.shader.current_shader = type;
|
||||||
if (!shader_backend_) { return; }
|
if (!shader_backend_) { return; }
|
||||||
if (!Options::video.postfx) {
|
if (!Options::video.shader.enabled) {
|
||||||
// Shaders desactivados: guardar preferencia pero mantener pass-through
|
// Shaders desactivados: guardar preferencia pero mantener pass-through
|
||||||
shader_backend_->setActiveShader(Rendering::ShaderType::POSTFX);
|
shader_backend_->setActiveShader(Rendering::ShaderType::POSTFX);
|
||||||
shader_backend_->setPostFXParams(Rendering::PostFXParams{});
|
shader_backend_->setPostFXParams(Rendering::PostFXParams{});
|
||||||
@@ -620,7 +592,7 @@ void Screen::setActiveShader(Rendering::ShaderType type) {
|
|||||||
|
|
||||||
// Cicla al siguiente shader disponible (preparado para futura UI)
|
// Cicla al siguiente shader disponible (preparado para futura UI)
|
||||||
void Screen::nextShader() {
|
void Screen::nextShader() {
|
||||||
const Rendering::ShaderType NEXT = (Options::current_shader == Rendering::ShaderType::POSTFX)
|
const Rendering::ShaderType NEXT = (Options::video.shader.current_shader == Rendering::ShaderType::POSTFX)
|
||||||
? Rendering::ShaderType::CRTPI
|
? Rendering::ShaderType::CRTPI
|
||||||
: Rendering::ShaderType::POSTFX;
|
: Rendering::ShaderType::POSTFX;
|
||||||
setActiveShader(NEXT);
|
setActiveShader(NEXT);
|
||||||
@@ -634,7 +606,8 @@ void Screen::initShaders() {
|
|||||||
|
|
||||||
if (!shader_backend_) {
|
if (!shader_backend_) {
|
||||||
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
|
shader_backend_ = std::make_unique<Rendering::SDL3GPUShader>();
|
||||||
shader_backend_->setPreferredDriver(Options::video.gpu_preferred_driver);
|
const std::string fallback_driver = "none";
|
||||||
|
shader_backend_->setPreferredDriver(Options::video.gpu.acceleration ? Options::video.gpu.preferred_driver : fallback_driver);
|
||||||
}
|
}
|
||||||
shader_backend_->init(window_, tex, "", "");
|
shader_backend_->init(window_, tex, "", "");
|
||||||
gpu_driver_ = shader_backend_->getDriverName();
|
gpu_driver_ = shader_backend_->getDriverName();
|
||||||
@@ -642,10 +615,10 @@ void Screen::initShaders() {
|
|||||||
// Propagar flags de vsync, integer scale, upscale y downscale al backend GPU
|
// Propagar flags de vsync, integer scale, upscale y downscale al backend GPU
|
||||||
shader_backend_->setVSync(Options::video.vertical_sync);
|
shader_backend_->setVSync(Options::video.vertical_sync);
|
||||||
shader_backend_->setScaleMode(Options::video.integer_scale);
|
shader_backend_->setScaleMode(Options::video.integer_scale);
|
||||||
shader_backend_->setLinearUpscale(Options::video.linear_upscale);
|
shader_backend_->setLinearUpscale(Options::video.supersampling.linear_upscale);
|
||||||
shader_backend_->setDownscaleAlgo(Options::video.downscale_algo);
|
shader_backend_->setDownscaleAlgo(Options::video.supersampling.downscale_algo);
|
||||||
|
|
||||||
if (Options::video.postfx) {
|
if (Options::video.shader.enabled) {
|
||||||
applyCurrentPostFXPreset();
|
applyCurrentPostFXPreset();
|
||||||
} else {
|
} else {
|
||||||
// Pass-through: todos los efectos a 0, el shader solo copia la textura
|
// Pass-through: todos los efectos a 0, el shader solo copia la textura
|
||||||
@@ -653,8 +626,8 @@ void Screen::initShaders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Restaurar el shader activo guardado en config (y sus parámetros CrtPi si aplica)
|
// Restaurar el shader activo guardado en config (y sus parámetros CrtPi si aplica)
|
||||||
shader_backend_->setActiveShader(Options::current_shader);
|
shader_backend_->setActiveShader(Options::video.shader.current_shader);
|
||||||
if (Options::current_shader == Rendering::ShaderType::CRTPI) {
|
if (Options::video.shader.current_shader == Rendering::ShaderType::CRTPI) {
|
||||||
applyCurrentCrtPiPreset();
|
applyCurrentCrtPiPreset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
#include <utility> // Para std::pair
|
#include <utility> // Para std::pair
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "core/rendering/shader_backend.hpp" // Para Rendering::ShaderType, ShaderBackend
|
#include "core/rendering/palette_manager.hpp" // Para PaletteManager
|
||||||
#include "utils/utils.hpp" // Para Color
|
#include "core/rendering/shader_backend.hpp" // Para Rendering::ShaderType, ShaderBackend
|
||||||
|
#include "utils/utils.hpp" // Para Color
|
||||||
class Surface;
|
class Surface;
|
||||||
class Text;
|
class Text;
|
||||||
|
|
||||||
@@ -35,14 +36,15 @@ class Screen {
|
|||||||
void update(float delta_time); // Actualiza la lógica de la clase
|
void update(float delta_time); // Actualiza la lógica de la clase
|
||||||
|
|
||||||
// Video y ventana
|
// Video y ventana
|
||||||
void setVideoMode(bool mode); // Establece el modo de video
|
void setVideoMode(bool mode); // Establece el modo de video
|
||||||
void toggleVideoMode(); // Cambia entre pantalla completa y ventana
|
void toggleVideoMode(); // Cambia entre pantalla completa y ventana
|
||||||
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
|
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
|
||||||
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
|
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
|
||||||
auto decWindowZoom() -> bool; // Reduce el tamaño de la ventana
|
auto decWindowZoom() -> bool; // Reduce el tamaño de la ventana
|
||||||
auto incWindowZoom() -> bool; // Aumenta el tamaño de la ventana
|
auto incWindowZoom() -> bool; // Aumenta el tamaño de la ventana
|
||||||
void show(); // Muestra la ventana
|
auto setWindowZoom(int zoom) -> bool; // Establece zoom directo; false si fuera de [1, max_zoom]
|
||||||
void hide(); // Oculta la ventana
|
void show(); // Muestra la ventana
|
||||||
|
void hide(); // Oculta la ventana
|
||||||
|
|
||||||
// Borde
|
// Borde
|
||||||
void setBorderColor(Uint8 color); // Cambia el color del borde
|
void setBorderColor(Uint8 color); // Cambia el color del borde
|
||||||
@@ -52,17 +54,22 @@ class Screen {
|
|||||||
void toggleBorder(); // Cambia entre borde visible y no visible
|
void toggleBorder(); // Cambia entre borde visible y no visible
|
||||||
|
|
||||||
// Paletas y PostFX
|
// Paletas y PostFX
|
||||||
void nextPalette(); // Cambia a la siguiente paleta
|
void nextPalette(); // Cambia a la siguiente paleta
|
||||||
void previousPalette(); // Cambia a la paleta anterior
|
void previousPalette(); // Cambia a la paleta anterior
|
||||||
void setPalete(); // Establece la paleta actual
|
auto setPaletteByName(const std::string& name) -> bool; // Cambia a paleta por nombre; false si no existe
|
||||||
void toggleShaders(); // Activa/desactiva todos los shaders respetando current_shader
|
[[nodiscard]] auto getPaletteNames() const -> std::vector<std::string>; // Nombres disponibles (minúsculas, sin .pal)
|
||||||
void toggleSupersampling(); // Activa/desactiva el supersampling global
|
[[nodiscard]] auto getPalettePrettyName() const -> std::string; // Nombre actual con guiones sustituidos por espacios
|
||||||
void reloadPostFX(); // Recarga el shader del preset actual sin toggle
|
void nextPaletteSortMode(); // Cicla al siguiente modo de ordenación de paleta
|
||||||
void reloadCrtPi(); // Recarga el shader CrtPi del preset actual sin toggle
|
void setPaletteSortMode(PaletteSortMode mode); // Establece modo de ordenación concreto
|
||||||
void setLinearUpscale(bool linear); // Upscale NEAREST (false) o LINEAR (true) en el paso SS
|
[[nodiscard]] auto getPaletteSortModeName() const -> std::string; // Nombre del modo de ordenación actual
|
||||||
void setDownscaleAlgo(int algo); // 0=bilinear legacy, 1=Lanczos2, 2=Lanczos3
|
void toggleShaders(); // Activa/desactiva todos los shaders respetando current_shader
|
||||||
void setActiveShader(Rendering::ShaderType type); // Cambia el shader de post-procesado activo
|
void toggleSupersampling(); // Activa/desactiva el supersampling global
|
||||||
void nextShader(); // Cicla al siguiente shader disponible (para futura UI)
|
void reloadPostFX(); // Recarga el shader del preset actual sin toggle
|
||||||
|
void reloadCrtPi(); // Recarga el shader CrtPi del preset actual sin toggle
|
||||||
|
void setLinearUpscale(bool linear); // Upscale NEAREST (false) o LINEAR (true) en el paso SS
|
||||||
|
void setDownscaleAlgo(int algo); // 0=bilinear legacy, 1=Lanczos2, 2=Lanczos3
|
||||||
|
void setActiveShader(Rendering::ShaderType type); // Cambia el shader de post-procesado activo
|
||||||
|
void nextShader(); // Cicla al siguiente shader disponible (para futura UI)
|
||||||
|
|
||||||
// Surfaces y notificaciones
|
// Surfaces y notificaciones
|
||||||
void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces
|
void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces
|
||||||
@@ -77,8 +84,10 @@ class Screen {
|
|||||||
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; }
|
[[nodiscard]] auto getText() const -> std::shared_ptr<Text> { return text_; }
|
||||||
[[nodiscard]] auto getGameSurfaceDstRect() const -> SDL_FRect { return game_surface_dstrect_; }
|
[[nodiscard]] auto getGameSurfaceDstRect() const -> SDL_FRect { return game_surface_dstrect_; }
|
||||||
[[nodiscard]] auto getGPUDriver() const -> const std::string& { return gpu_driver_; }
|
[[nodiscard]] auto getGPUDriver() const -> const std::string& { return gpu_driver_; }
|
||||||
|
[[nodiscard]] auto isHardwareAccelerated() const -> bool { return shader_backend_ && shader_backend_->isHardwareAccelerated(); }
|
||||||
[[nodiscard]] auto getLastFPS() const -> int { return fps_.last_value; }
|
[[nodiscard]] auto getLastFPS() const -> int { return fps_.last_value; }
|
||||||
[[nodiscard]] auto getZoomFactor() const -> float { return zoom_factor_; }
|
[[nodiscard]] auto getZoomFactor() const -> float { return zoom_factor_; }
|
||||||
|
[[nodiscard]] auto getMaxZoom() const -> int;
|
||||||
[[nodiscard]] auto getSsTextureSize() const -> std::pair<int, int>;
|
[[nodiscard]] auto getSsTextureSize() const -> std::pair<int, int>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -116,20 +125,18 @@ class Screen {
|
|||||||
static Screen* screen;
|
static Screen* screen;
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
void renderNotifications() const; // Dibuja las notificaciones
|
void renderNotifications() const; // Dibuja las notificaciones
|
||||||
void adjustWindowSize(); // Calcula el tamaño de la ventana
|
void adjustWindowSize(); // Calcula el tamaño de la ventana
|
||||||
void adjustRenderLogicalSize(); // Ajusta el tamaño lógico del renderizador
|
void adjustRenderLogicalSize(); // Ajusta el tamaño lógico del renderizador
|
||||||
void processPaletteList(); // Extrae los nombres de las paletas
|
void surfaceToTexture(); // Copia la surface a la textura
|
||||||
void surfaceToTexture(); // Copia la surface a la textura
|
void textureToRenderer(); // Copia la textura al renderizador
|
||||||
void textureToRenderer(); // Copia la textura al renderizador
|
void renderOverlays(); // Renderiza todos los overlays
|
||||||
void renderOverlays(); // Renderiza todos los overlays
|
void initShaders(); // Inicializa los shaders
|
||||||
auto findPalette(const std::string& name) -> size_t; // Localiza la paleta dentro del vector de paletas
|
void applyCurrentPostFXPreset(); // Aplica los parámetros del preset PostFX actual al backend
|
||||||
void initShaders(); // Inicializa los shaders
|
void applyCurrentCrtPiPreset(); // Aplica los parámetros del preset CrtPi actual al backend
|
||||||
void applyCurrentPostFXPreset(); // Aplica los parámetros del preset PostFX actual al backend
|
void getDisplayInfo(); // Obtiene información sobre la pantalla
|
||||||
void applyCurrentCrtPiPreset(); // Aplica los parámetros del preset CrtPi actual al backend
|
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
||||||
void getDisplayInfo(); // Obtiene información sobre la pantalla
|
void createText(); // Crea el objeto de texto
|
||||||
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
|
||||||
void createText(); // Crea el objeto de texto
|
|
||||||
|
|
||||||
// Constructor y destructor
|
// Constructor y destructor
|
||||||
Screen();
|
Screen();
|
||||||
@@ -163,9 +170,8 @@ class Screen {
|
|||||||
SDL_FRect game_surface_dstrect_; // Coordenadas donde se dibuja la textura del juego
|
SDL_FRect game_surface_dstrect_; // Coordenadas donde se dibuja la textura del juego
|
||||||
|
|
||||||
// Paletas y colores
|
// Paletas y colores
|
||||||
Uint8 border_color_{0}; // Color del borde
|
Uint8 border_color_{0}; // Color del borde
|
||||||
std::vector<std::string> palettes_; // Listado de ficheros de paleta disponibles
|
std::unique_ptr<PaletteManager> palette_manager_; // Gestor de paletas de color
|
||||||
Uint8 current_palette_{0}; // Índice para el vector de paletas
|
|
||||||
|
|
||||||
// Estado y configuración
|
// Estado y configuración
|
||||||
bool notifications_enabled_{false}; // Indica si se muestran las notificaciones
|
bool notifications_enabled_{false}; // Indica si se muestran las notificaciones
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -403,7 +403,7 @@ namespace Rendering {
|
|||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
if (preferred_driver_ == "none") {
|
if (preferred_driver_ == "none") {
|
||||||
SDL_Log("SDL3GPUShader: GPU disabled by config, using SDL_Renderer fallback");
|
SDL_Log("SDL3GPUShader: GPU disabled by config, using SDL_Renderer fallback");
|
||||||
driver_name_ = "none";
|
driver_name_ = ""; // vacío → RenderInfo mostrará "sdl"
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (device_ == nullptr) {
|
if (device_ == nullptr) {
|
||||||
|
|||||||
@@ -1,59 +1,633 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
static const uint8_t kupscale_frag_spv[] = {
|
static const uint8_t kupscale_frag_spv[] = {
|
||||||
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,
|
0x03,
|
||||||
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
|
0x02,
|
||||||
0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
|
0x23,
|
||||||
0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,
|
0x07,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
0x01,
|
||||||
0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
|
0x00,
|
||||||
0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00,
|
0x0b,
|
||||||
0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00,
|
0x00,
|
||||||
0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70,
|
0x0d,
|
||||||
0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65,
|
0x00,
|
||||||
0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00,
|
0x14,
|
||||||
0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,
|
0x00,
|
||||||
0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69,
|
0x00,
|
||||||
0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00,
|
0x00,
|
||||||
0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x5f,
|
0x00,
|
||||||
0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00,
|
0x00,
|
||||||
0x0d, 0x00, 0x00, 0x00, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x05, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x76, 0x5f, 0x75, 0x76,
|
0x11,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,
|
0x02,
|
||||||
0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
0x01,
|
||||||
0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00,
|
0x00,
|
||||||
0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00,
|
0x0b,
|
||||||
0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,
|
0x06,
|
||||||
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
|
0x01,
|
||||||
0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
0x47,
|
||||||
0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
0x4c,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
0x53,
|
||||||
0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x4c,
|
||||||
0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
0x2e,
|
||||||
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
0x73,
|
||||||
0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,
|
0x74,
|
||||||
0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
0x64,
|
||||||
0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
0x2e,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,
|
0x34,
|
||||||
0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,
|
0x35,
|
||||||
0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,
|
0x30,
|
||||||
0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
|
0x00,
|
||||||
0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,
|
0x00,
|
||||||
0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00,
|
0x00,
|
||||||
0x38, 0x00, 0x01, 0x00
|
0x0e,
|
||||||
};
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0f,
|
||||||
|
0x00,
|
||||||
|
0x07,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x6d,
|
||||||
|
0x61,
|
||||||
|
0x69,
|
||||||
|
0x6e,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x09,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x11,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x10,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x07,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0xc2,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0a,
|
||||||
|
0x00,
|
||||||
|
0x47,
|
||||||
|
0x4c,
|
||||||
|
0x5f,
|
||||||
|
0x47,
|
||||||
|
0x4f,
|
||||||
|
0x4f,
|
||||||
|
0x47,
|
||||||
|
0x4c,
|
||||||
|
0x45,
|
||||||
|
0x5f,
|
||||||
|
0x63,
|
||||||
|
0x70,
|
||||||
|
0x70,
|
||||||
|
0x5f,
|
||||||
|
0x73,
|
||||||
|
0x74,
|
||||||
|
0x79,
|
||||||
|
0x6c,
|
||||||
|
0x65,
|
||||||
|
0x5f,
|
||||||
|
0x6c,
|
||||||
|
0x69,
|
||||||
|
0x6e,
|
||||||
|
0x65,
|
||||||
|
0x5f,
|
||||||
|
0x64,
|
||||||
|
0x69,
|
||||||
|
0x72,
|
||||||
|
0x65,
|
||||||
|
0x63,
|
||||||
|
0x74,
|
||||||
|
0x69,
|
||||||
|
0x76,
|
||||||
|
0x65,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x08,
|
||||||
|
0x00,
|
||||||
|
0x47,
|
||||||
|
0x4c,
|
||||||
|
0x5f,
|
||||||
|
0x47,
|
||||||
|
0x4f,
|
||||||
|
0x4f,
|
||||||
|
0x47,
|
||||||
|
0x4c,
|
||||||
|
0x45,
|
||||||
|
0x5f,
|
||||||
|
0x69,
|
||||||
|
0x6e,
|
||||||
|
0x63,
|
||||||
|
0x6c,
|
||||||
|
0x75,
|
||||||
|
0x64,
|
||||||
|
0x65,
|
||||||
|
0x5f,
|
||||||
|
0x64,
|
||||||
|
0x69,
|
||||||
|
0x72,
|
||||||
|
0x65,
|
||||||
|
0x63,
|
||||||
|
0x74,
|
||||||
|
0x69,
|
||||||
|
0x76,
|
||||||
|
0x65,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x6d,
|
||||||
|
0x61,
|
||||||
|
0x69,
|
||||||
|
0x6e,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x09,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x6f,
|
||||||
|
0x75,
|
||||||
|
0x74,
|
||||||
|
0x5f,
|
||||||
|
0x63,
|
||||||
|
0x6f,
|
||||||
|
0x6c,
|
||||||
|
0x6f,
|
||||||
|
0x72,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0d,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x73,
|
||||||
|
0x63,
|
||||||
|
0x65,
|
||||||
|
0x6e,
|
||||||
|
0x65,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x11,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x76,
|
||||||
|
0x5f,
|
||||||
|
0x75,
|
||||||
|
0x76,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x47,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x09,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x1e,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x47,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0d,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x21,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x47,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0d,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x22,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x47,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x11,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x1e,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x13,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x21,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x16,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x06,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x20,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x17,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x07,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x06,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x20,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x08,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x07,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x3b,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x08,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x09,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x19,
|
||||||
|
0x00,
|
||||||
|
0x09,
|
||||||
|
0x00,
|
||||||
|
0x0a,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x06,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x1b,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x0b,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0a,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x20,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0c,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0b,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x3b,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0c,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0d,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x17,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0f,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x06,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x20,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x10,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0f,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x3b,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x10,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x11,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x36,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0xf8,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x3d,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0b,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0e,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0d,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x3d,
|
||||||
|
0x00,
|
||||||
|
0x04,
|
||||||
|
0x00,
|
||||||
|
0x0f,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x12,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x11,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x57,
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x00,
|
||||||
|
0x07,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x13,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x0e,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x12,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x3e,
|
||||||
|
0x00,
|
||||||
|
0x03,
|
||||||
|
0x00,
|
||||||
|
0x09,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x13,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0xfd,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00,
|
||||||
|
0x38,
|
||||||
|
0x00,
|
||||||
|
0x01,
|
||||||
|
0x00};
|
||||||
static const size_t kupscale_frag_spv_size = 628;
|
static const size_t kupscale_frag_spv_size = 628;
|
||||||
|
|||||||
@@ -175,12 +175,12 @@ void Surface::fillRect(const SDL_FRect* rect, Uint8 color) { // NOLINT(readabil
|
|||||||
float x_end = std::min(rect->x + rect->w, surface_data_->width);
|
float x_end = std::min(rect->x + rect->w, surface_data_->width);
|
||||||
float y_end = std::min(rect->y + rect->h, surface_data_->height);
|
float y_end = std::min(rect->y + rect->h, surface_data_->height);
|
||||||
|
|
||||||
// Recorrer cada píxel dentro del rectángulo directamente
|
// Rellenar fila a fila con memset (memoria contigua por fila)
|
||||||
for (int y = y_start; y < y_end; ++y) {
|
Uint8* data_ptr = surface_data_->data.get();
|
||||||
for (int x = x_start; x < x_end; ++x) {
|
const int surf_width = static_cast<int>(surface_data_->width);
|
||||||
const int INDEX = x + (y * surface_data_->width);
|
const int row_width = static_cast<int>(x_end) - static_cast<int>(x_start);
|
||||||
surface_data_->data.get()[INDEX] = color;
|
for (int y = static_cast<int>(y_start); y < static_cast<int>(y_end); ++y) {
|
||||||
}
|
std::memset(data_ptr + (y * surf_width) + static_cast<int>(x_start), color, row_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,16 +192,12 @@ void Surface::drawRectBorder(const SDL_FRect* rect, Uint8 color) { // NOLINT(re
|
|||||||
float x_end = std::min(rect->x + rect->w, surface_data_->width);
|
float x_end = std::min(rect->x + rect->w, surface_data_->width);
|
||||||
float y_end = std::min(rect->y + rect->h, surface_data_->height);
|
float y_end = std::min(rect->y + rect->h, surface_data_->height);
|
||||||
|
|
||||||
// Dibujar bordes horizontales
|
// Dibujar bordes horizontales con memset (líneas contiguas en memoria)
|
||||||
for (int x = x_start; x < x_end; ++x) {
|
Uint8* data_ptr = surface_data_->data.get();
|
||||||
// Borde superior
|
const int surf_width = static_cast<int>(surface_data_->width);
|
||||||
const int TOP_INDEX = x + (y_start * surface_data_->width);
|
const int row_width = static_cast<int>(x_end) - static_cast<int>(x_start);
|
||||||
surface_data_->data.get()[TOP_INDEX] = color;
|
std::memset(data_ptr + (static_cast<int>(y_start) * surf_width) + static_cast<int>(x_start), color, row_width);
|
||||||
|
std::memset(data_ptr + ((static_cast<int>(y_end) - 1) * surf_width) + static_cast<int>(x_start), color, row_width);
|
||||||
// Borde inferior
|
|
||||||
const int BOTTOM_INDEX = x + ((y_end - 1) * surface_data_->width);
|
|
||||||
surface_data_->data.get()[BOTTOM_INDEX] = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dibujar bordes verticales
|
// Dibujar bordes verticales
|
||||||
for (int y = y_start; y < y_end; ++y) {
|
for (int y = y_start; y < y_end; ++y) {
|
||||||
@@ -261,6 +257,8 @@ void Surface::render(float dx, float dy, float sx, float sy, float w, float h) {
|
|||||||
w = std::min(w, surface_data->width - dx);
|
w = std::min(w, surface_data->width - dx);
|
||||||
h = std::min(h, surface_data->height - dy);
|
h = std::min(h, surface_data->height - dy);
|
||||||
|
|
||||||
|
const Uint8* src_ptr = surface_data_->data.get();
|
||||||
|
Uint8* dst_ptr = surface_data->data.get();
|
||||||
for (int iy = 0; iy < h; ++iy) {
|
for (int iy = 0; iy < h; ++iy) {
|
||||||
for (int ix = 0; ix < w; ++ix) {
|
for (int ix = 0; ix < w; ++ix) {
|
||||||
// Verificar que las coordenadas de destino están dentro de los límites
|
// Verificar que las coordenadas de destino están dentro de los límites
|
||||||
@@ -269,9 +267,9 @@ void Surface::render(float dx, float dy, float sx, float sy, float w, float h) {
|
|||||||
int src_x = sx + ix;
|
int src_x = sx + ix;
|
||||||
int src_y = sy + iy;
|
int src_y = sy + iy;
|
||||||
|
|
||||||
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
Uint8 color = src_ptr[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
||||||
if (color != static_cast<Uint8>(transparent_color_)) {
|
if (color != static_cast<Uint8>(transparent_color_)) {
|
||||||
surface_data->data.get()[static_cast<size_t>(dest_x + (dest_y * surface_data->width))] = sub_palette_[color];
|
dst_ptr[static_cast<size_t>(dest_x + (dest_y * surface_data->width))] = sub_palette_[color];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,6 +297,8 @@ void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { //
|
|||||||
h = std::min(h, surface_data_dest->height - y);
|
h = std::min(h, surface_data_dest->height - y);
|
||||||
|
|
||||||
// Renderiza píxel por píxel aplicando el flip si es necesario
|
// Renderiza píxel por píxel aplicando el flip si es necesario
|
||||||
|
const Uint8* src_ptr = surface_data_->data.get();
|
||||||
|
Uint8* dst_ptr = surface_data_dest->data.get();
|
||||||
for (int iy = 0; iy < h; ++iy) {
|
for (int iy = 0; iy < h; ++iy) {
|
||||||
for (int ix = 0; ix < w; ++ix) {
|
for (int ix = 0; ix < w; ++ix) {
|
||||||
// Coordenadas de origen
|
// Coordenadas de origen
|
||||||
@@ -312,9 +312,9 @@ void Surface::render(int x, int y, SDL_FRect* src_rect, SDL_FlipMode flip) { //
|
|||||||
// Verificar que las coordenadas de destino están dentro de los límites
|
// Verificar que las coordenadas de destino están dentro de los límites
|
||||||
if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) {
|
if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) {
|
||||||
// Copia el píxel si no es transparente
|
// Copia el píxel si no es transparente
|
||||||
Uint8 color = surface_data_->data.get()[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
Uint8 color = src_ptr[static_cast<size_t>(src_x + (src_y * surface_data_->width))];
|
||||||
if (color != static_cast<Uint8>(transparent_color_)) {
|
if (color != static_cast<Uint8>(transparent_color_)) {
|
||||||
surface_data_dest->data[dest_x + (dest_y * surface_data_dest->width)] = sub_palette_[color];
|
dst_ptr[static_cast<size_t>(dest_x + (dest_y * surface_data_dest->width))] = sub_palette_[color];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -567,13 +567,16 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) { //
|
|||||||
// Convertir `pitch` de bytes a Uint32 (asegurando alineación correcta en hardware)
|
// Convertir `pitch` de bytes a Uint32 (asegurando alineación correcta en hardware)
|
||||||
int row_stride = pitch / sizeof(Uint32);
|
int row_stride = pitch / sizeof(Uint32);
|
||||||
|
|
||||||
for (int y = 0; y < surface_data_->height; ++y) {
|
// Cachear punteros fuera del bucle para permitir autovectorización SIMD
|
||||||
for (int x = 0; x < surface_data_->width; ++x) {
|
const Uint8* src = surface_data_->data.get();
|
||||||
// Calcular la posición correcta en la textura teniendo en cuenta el stride
|
const Uint32* pal = palette_.data();
|
||||||
int texture_index = (y * row_stride) + x;
|
const int width = surface_data_->width;
|
||||||
int surface_index = (y * surface_data_->width) + x;
|
const int height = surface_data_->height;
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
pixels[texture_index] = palette_[surface_data_->data.get()[surface_index]];
|
const Uint8* src_row = src + (y * width);
|
||||||
|
Uint32* dst_row = pixels + (y * row_stride);
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
dst_row[x] = pal[src_row[x]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -613,12 +616,16 @@ void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_FR
|
|||||||
|
|
||||||
int row_stride = pitch / sizeof(Uint32);
|
int row_stride = pitch / sizeof(Uint32);
|
||||||
|
|
||||||
for (int y = 0; y < surface_data_->height; ++y) {
|
// Cachear punteros fuera del bucle para permitir autovectorización SIMD
|
||||||
for (int x = 0; x < surface_data_->width; ++x) {
|
const Uint8* src = surface_data_->data.get();
|
||||||
int texture_index = (y * row_stride) + x;
|
const Uint32* pal = palette_.data();
|
||||||
int surface_index = (y * surface_data_->width) + x;
|
const int width = surface_data_->width;
|
||||||
|
const int height = surface_data_->height;
|
||||||
pixels[texture_index] = palette_[surface_data_->data.get()[surface_index]];
|
for (int y = 0; y < height; ++y) {
|
||||||
|
const Uint8* src_row = src + (y * width);
|
||||||
|
Uint32* dst_row = pixels + (y * row_stride);
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
dst_row[x] = pal[src_row[x]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,8 +189,13 @@ Director::Director() {
|
|||||||
|
|
||||||
// Inicializa el sistema de localización (antes de Cheevos que usa textos traducidos)
|
// Inicializa el sistema de localización (antes de Cheevos que usa textos traducidos)
|
||||||
#ifdef RELEASE_BUILD
|
#ifdef RELEASE_BUILD
|
||||||
std::string locale_path = executable_path_ + PREFIX + "/data/locale/" + Options::language + ".yaml";
|
{
|
||||||
Locale::init(locale_path);
|
// En release el locale está en el pack, no en el filesystem
|
||||||
|
std::string locale_key = Resource::List::get()->get(Options::language + ".yaml"); // NOLINT(readability-static-accessed-through-instance)
|
||||||
|
auto locale_bytes = Resource::Helper::loadFile(locale_key);
|
||||||
|
std::string locale_content(locale_bytes.begin(), locale_bytes.end());
|
||||||
|
Locale::initFromContent(locale_content);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
Locale::init(Resource::List::get()->get(Options::language + ".yaml")); // NOLINT(readability-static-accessed-through-instance)
|
Locale::init(Resource::List::get()->get(Options::language + ".yaml")); // NOLINT(readability-static-accessed-through-instance)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,13 +25,15 @@ namespace Defaults::Video {
|
|||||||
constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana)
|
constexpr bool FULLSCREEN = false; // Modo de pantalla completa por defecto (false = ventana)
|
||||||
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
|
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
|
||||||
constexpr bool VERTICAL_SYNC = true; // Vsync activado por defecto
|
constexpr bool VERTICAL_SYNC = true; // Vsync activado por defecto
|
||||||
constexpr bool POSTFX = false; // PostFX desactivado por defecto
|
constexpr bool SHADER_ENABLED = false; // Shaders de post-procesado desactivados por defecto
|
||||||
constexpr bool SUPERSAMPLING = false; // Supersampling desactivado por defecto
|
constexpr bool SUPERSAMPLING = false; // Supersampling desactivado por defecto
|
||||||
constexpr bool INTEGER_SCALE = true; // Escalado entero activado por defecto
|
constexpr bool INTEGER_SCALE = true; // Escalado entero activado por defecto
|
||||||
constexpr bool KEEP_ASPECT = true; // Mantener aspecto activado por defecto
|
constexpr bool KEEP_ASPECT = true; // Mantener aspecto activado por defecto
|
||||||
constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto
|
constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto
|
||||||
|
constexpr const char* PALETTE_SORT = "original"; // Modo de ordenación de paleta por defecto
|
||||||
constexpr bool LINEAR_UPSCALE = false; // Upscale NEAREST por defecto
|
constexpr bool LINEAR_UPSCALE = false; // Upscale NEAREST por defecto
|
||||||
constexpr int DOWNSCALE_ALGO = 1; // Downscale Lanczos2 por defecto
|
constexpr int DOWNSCALE_ALGO = 1; // Downscale Lanczos2 por defecto
|
||||||
|
constexpr bool GPU_ACCELERATION = true; // Aceleración GPU activada por defecto
|
||||||
} // namespace Defaults::Video
|
} // namespace Defaults::Video
|
||||||
|
|
||||||
namespace Defaults::Border {
|
namespace Defaults::Border {
|
||||||
@@ -100,5 +102,6 @@ namespace Defaults::Game::Player {
|
|||||||
constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial
|
constexpr int SPAWN_X = 25 * Tile::SIZE; // Posición X inicial
|
||||||
constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial
|
constexpr int SPAWN_Y = 13 * Tile::SIZE; // Posición Y inicial
|
||||||
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial
|
constexpr SDL_FlipMode SPAWN_FLIP = Flip::LEFT; // Orientación inicial
|
||||||
constexpr int SKIN = 1; // Skin del jugador por defecto (1=normal, 2=alternativa)
|
constexpr const char* SKIN = "default"; // Skin del jugador por defecto
|
||||||
|
constexpr int COLOR = -1; // Color del jugador (-1 = automático según cheats)
|
||||||
} // namespace Defaults::Game::Player
|
} // namespace Defaults::Game::Player
|
||||||
|
|||||||
@@ -620,20 +620,26 @@ auto Player::handleKillingTiles() -> bool {
|
|||||||
return false; // No se encontró ninguna colisión
|
return false; // No se encontró ninguna colisión
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establece el color del jugador (0 = automático según cheats)
|
// Establece el color del jugador (0 = automático según options)
|
||||||
void Player::setColor(Uint8 color) {
|
void Player::setColor(Uint8 color) {
|
||||||
if (color != 0) {
|
if (color != 0) {
|
||||||
color_ = color;
|
color_ = color;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
|
// Color personalizado desde opciones
|
||||||
color_ = static_cast<Uint8>(PaletteColor::CYAN);
|
if (Options::game.player_color >= 0) {
|
||||||
} else if (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED) {
|
color_ = static_cast<Uint8>(Options::game.player_color);
|
||||||
color_ = static_cast<Uint8>(PaletteColor::YELLOW);
|
|
||||||
} else {
|
} else {
|
||||||
color_ = static_cast<Uint8>(PaletteColor::WHITE);
|
color_ = static_cast<Uint8>(PaletteColor::WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si el color coincide con el fondo de la habitación, usar fallback
|
||||||
|
if (room_ != nullptr && color_ == room_->getBGColor()) {
|
||||||
|
color_ = (room_->getBGColor() != static_cast<Uint8>(PaletteColor::WHITE))
|
||||||
|
? static_cast<Uint8>(PaletteColor::WHITE)
|
||||||
|
: static_cast<Uint8>(PaletteColor::BRIGHT_BLACK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza los puntos de colisión
|
// Actualiza los puntos de colisión
|
||||||
@@ -765,11 +771,18 @@ void Player::applySpawnValues(const SpawnData& spawn) {
|
|||||||
sprite_->setFlip(spawn.flip);
|
sprite_->setFlip(spawn.flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resuelve nombre de skin a fichero de animación
|
||||||
|
auto Player::skinToAnimationPath(const std::string& skin_name) -> std::string {
|
||||||
|
if (skin_name == "default") {
|
||||||
|
return "player.yaml";
|
||||||
|
}
|
||||||
|
return skin_name + ".yaml";
|
||||||
|
}
|
||||||
|
|
||||||
// Cambia la skin del jugador en caliente preservando la orientación actual
|
// Cambia la skin del jugador en caliente preservando la orientación actual
|
||||||
void Player::setSkin(int skin_num) {
|
void Player::setSkin(const std::string& skin_name) {
|
||||||
const auto FLIP = sprite_->getFlip();
|
const auto FLIP = sprite_->getFlip();
|
||||||
const std::string PATH = (skin_num == 2) ? "player2.yaml" : "player.yaml";
|
initSprite(skinToAnimationPath(skin_name));
|
||||||
initSprite(PATH);
|
|
||||||
sprite_->setFlip(FLIP);
|
sprite_->setFlip(FLIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,7 +792,7 @@ void Player::initSprite(const std::string& animations_path) { // NOLINT(readabi
|
|||||||
sprite_ = std::make_unique<AnimatedSprite>(animation_data);
|
sprite_ = std::make_unique<AnimatedSprite>(animation_data);
|
||||||
sprite_->setWidth(WIDTH);
|
sprite_->setWidth(WIDTH);
|
||||||
sprite_->setHeight(HEIGHT);
|
sprite_->setHeight(HEIGHT);
|
||||||
sprite_->setCurrentAnimation("walk");
|
sprite_->setCurrentAnimation("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza la posición del sprite y las colisiones
|
// Actualiza la posición del sprite y las colisiones
|
||||||
@@ -880,6 +893,10 @@ auto Player::handleLandingFromAir(float displacement, const SDL_FRect& projectio
|
|||||||
|
|
||||||
// No hay colisión
|
// No hay colisión
|
||||||
y_ += displacement;
|
y_ += displacement;
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Guarda por si en debug el jugador se sale de la pantalla, para que no esté cayendo infinitamente
|
||||||
|
if (y_ > PlayArea::BOTTOM + HEIGHT) { y_ = PlayArea::TOP + 2; }
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,12 +100,14 @@ class Player {
|
|||||||
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
|
auto getCollider() -> SDL_FRect& { return collider_box_; } // Obtiene el rectangulo de colision del jugador
|
||||||
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
|
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; } // Obtiene el estado de reaparición del jugador
|
||||||
void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats)
|
void setColor(Uint8 color = 0); // Establece el color del jugador (0 = automático según cheats)
|
||||||
void setSkin(int skin_num); // Cambia la skin del jugador en caliente (1=normal, 2=alternativa)
|
void setSkin(const std::string& skin_name); // Cambia la skin del jugador en caliente ("default" o nombre de enemigo)
|
||||||
|
static auto skinToAnimationPath(const std::string& skin_name) -> std::string; // Resuelve nombre de skin a fichero de animación
|
||||||
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador
|
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); } // Establece la habitación en la que se encuentra el jugador
|
||||||
//[[nodiscard]] auto isAlive() const -> bool { return is_alive_ || (Options::cheats.invincible == Options::Cheat::State::ENABLED); } // Comprueba si el jugador esta vivo
|
//[[nodiscard]] auto isAlive() const -> bool { return is_alive_ || (Options::cheats.invincible == Options::Cheat::State::ENABLED); } // Comprueba si el jugador esta vivo
|
||||||
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo
|
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; } // Comprueba si el jugador esta vivo
|
||||||
void setPaused(bool value) { is_paused_ = value; } // Pone el jugador en modo pausa
|
void setPaused(bool value) { is_paused_ = value; } // Pone el jugador en modo pausa
|
||||||
void setIgnoreInput(bool value) { ignore_input_ = value; } // Ignora inputs del jugador (física sigue activa)
|
void setIgnoreInput(bool value) { ignore_input_ = value; } // Ignora inputs del jugador (física sigue activa)
|
||||||
|
[[nodiscard]] auto getIgnoreInput() const -> bool { return ignore_input_; }
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
// --- Funciones de debug ---
|
// --- Funciones de debug ---
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace GameControl {
|
namespace GameControl {
|
||||||
// Disponible en todos los builds — refresca el color del jugador según cheats
|
// Disponible en todos los builds — cambia la skin del jugador ("default" o nombre de enemigo)
|
||||||
inline std::function<void()> refresh_player_color;
|
inline std::function<void(const std::string&)> change_player_skin;
|
||||||
// Disponible en todos los builds — cambia la skin del jugador (1=normal, 2=alternativa)
|
// Disponible en todos los builds — cambia el color del jugador (-1 = automático, 0-15 = color fijo)
|
||||||
inline std::function<void(int)> change_player_skin;
|
inline std::function<void(int)> change_player_color;
|
||||||
} // namespace GameControl
|
} // namespace GameControl
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "core/rendering/surface.hpp" // Para Surface
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
#include "core/rendering/text.hpp" // Para Text
|
#include "core/rendering/text.hpp" // Para Text
|
||||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||||
|
#include "game/entities/player.hpp" // Para Player::skinToAnimationPath
|
||||||
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
|
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
|
||||||
#include "utils/defines.hpp" // Para BLOCK
|
#include "utils/defines.hpp" // Para BLOCK
|
||||||
#include "utils/utils.hpp" // Para stringToColor
|
#include "utils/utils.hpp" // Para stringToColor
|
||||||
@@ -22,9 +23,10 @@ Scoreboard::Scoreboard(std::shared_ptr<Data> data)
|
|||||||
constexpr float SURFACE_HEIGHT = 6.0F * Tile::SIZE;
|
constexpr float SURFACE_HEIGHT = 6.0F * Tile::SIZE;
|
||||||
|
|
||||||
// Reserva memoria para los objetos
|
// Reserva memoria para los objetos
|
||||||
const auto& player_animation_data = Resource::Cache::get()->getAnimationData((Options::game.player_skin == 2) ? "player2.yaml" : "player.yaml");
|
const std::string player_anim_path = Player::skinToAnimationPath(Options::game.player_skin);
|
||||||
|
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(player_anim_path);
|
||||||
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
||||||
player_sprite_->setCurrentAnimation("walk_menu");
|
player_sprite_->setCurrentAnimation("default");
|
||||||
|
|
||||||
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
|
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
|
||||||
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
|
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
|
||||||
@@ -49,9 +51,6 @@ void Scoreboard::update(float delta_time) {
|
|||||||
// Acumular tiempo para animaciones
|
// Acumular tiempo para animaciones
|
||||||
time_accumulator_ += delta_time;
|
time_accumulator_ += delta_time;
|
||||||
|
|
||||||
// Actualizar sprite con delta time
|
|
||||||
player_sprite_->update(delta_time);
|
|
||||||
|
|
||||||
// Actualiza el color de la cantidad de items recogidos
|
// Actualiza el color de la cantidad de items recogidos
|
||||||
updateItemsColor(delta_time);
|
updateItemsColor(delta_time);
|
||||||
|
|
||||||
@@ -77,6 +76,14 @@ auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-con
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Actualiza el sprite del jugador con la skin actual
|
||||||
|
void Scoreboard::refreshPlayerSkin() {
|
||||||
|
const std::string player_anim_path = Player::skinToAnimationPath(Options::game.player_skin);
|
||||||
|
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(player_anim_path);
|
||||||
|
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
||||||
|
player_sprite_->setCurrentAnimation("default");
|
||||||
|
}
|
||||||
|
|
||||||
// Pone el marcador en modo pausa
|
// Pone el marcador en modo pausa
|
||||||
void Scoreboard::setPaused(bool value) {
|
void Scoreboard::setPaused(bool value) {
|
||||||
if (is_paused_ == value) {
|
if (is_paused_ == value) {
|
||||||
@@ -130,18 +137,14 @@ void Scoreboard::fillTexture() {
|
|||||||
// Limpia la textura
|
// Limpia la textura
|
||||||
surface_->clear(stringToColor("black"));
|
surface_->clear(stringToColor("black"));
|
||||||
|
|
||||||
// Anclas
|
|
||||||
constexpr int LINE1 = Tile::SIZE;
|
|
||||||
constexpr int LINE2 = 3 * Tile::SIZE;
|
|
||||||
|
|
||||||
// Dibuja las vidas
|
// Dibuja las vidas
|
||||||
// Calcular desplazamiento basado en tiempo
|
const int WALK_FRAMES = player_sprite_->getCurrentAnimationSize();
|
||||||
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % 8;
|
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % (WALK_FRAMES * 2);
|
||||||
const int FRAME = DESP % SPRITE_WALK_FRAMES;
|
const int FRAME = DESP % WALK_FRAMES;
|
||||||
player_sprite_->setCurrentAnimationFrame(FRAME);
|
player_sprite_->setCurrentAnimationFrame(FRAME);
|
||||||
player_sprite_->setPosY(LINE2);
|
player_sprite_->setPosY(LINE2_Y);
|
||||||
for (int i = 0; i < data_->lives; ++i) {
|
for (int i = 0; i < data_->lives; ++i) {
|
||||||
player_sprite_->setPosX(8 + (16 * i) + DESP);
|
player_sprite_->setPosX(LIVES_START_X + (LIVES_SPACING * i) + DESP);
|
||||||
const int INDEX = i % color_.size();
|
const int INDEX = i % color_.size();
|
||||||
player_sprite_->render(1, color_.at(INDEX));
|
player_sprite_->render(1, color_.at(INDEX));
|
||||||
}
|
}
|
||||||
@@ -150,21 +153,30 @@ void Scoreboard::fillTexture() {
|
|||||||
if (data_->music) {
|
if (data_->music) {
|
||||||
const Uint8 C = data_->color;
|
const Uint8 C = data_->color;
|
||||||
SDL_FRect clip = {.x = 0, .y = 8, .w = 8, .h = 8};
|
SDL_FRect clip = {.x = 0, .y = 8, .w = 8, .h = 8};
|
||||||
item_surface_->renderWithColorReplace(20 * Tile::SIZE, LINE2, 1, C, &clip);
|
item_surface_->renderWithColorReplace(MUSIC_ICON_X, LINE2_Y, 1, C, &clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escribe los textos
|
// Escribe los textos
|
||||||
auto text = Resource::Cache::get()->getText("smb2");
|
auto text = Resource::Cache::get()->getText("smb2");
|
||||||
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
|
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
|
||||||
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
|
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
|
||||||
text->writeColored(Tile::SIZE, LINE1, Locale::get()->get("scoreboard.items"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
text->writeColored(ITEMS_LABEL_X, LINE1_Y, Locale::get()->get("scoreboard.items"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||||
text->writeColored(17 * Tile::SIZE, LINE1, ITEMS_TEXT, items_color_);
|
text->writeColored(ITEMS_VALUE_X, LINE1_Y, ITEMS_TEXT, items_color_);
|
||||||
text->writeColored(20 * Tile::SIZE, LINE1, Locale::get()->get("scoreboard.time"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
text->writeColored(TIME_LABEL_X, LINE1_Y, Locale::get()->get("scoreboard.time"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||||
text->writeColored(26 * Tile::SIZE, LINE1, TIME_TEXT, stringToColor("white"));
|
text->writeColored(TIME_VALUE_X, LINE1_Y, TIME_TEXT, stringToColor("white"));
|
||||||
|
|
||||||
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
|
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
|
||||||
text->writeColored(22 * Tile::SIZE, LINE2, Locale::get()->get("scoreboard.rooms"), stringToColor("white")); // NOLINT(readability-static-accessed-through-instance)
|
text->writeColored(ROOMS_LABEL_X, LINE2_Y, Locale::get()->get("scoreboard.rooms"), stringToColor("white")); // NOLINT(readability-static-accessed-through-instance)
|
||||||
text->writeColored(28 * Tile::SIZE, LINE2, ROOMS_TEXT, stringToColor("white"));
|
text->writeColored(ROOMS_VALUE_X, LINE2_Y, ROOMS_TEXT, stringToColor("white"));
|
||||||
|
|
||||||
|
// Indicadores de trucos activos (fuente 8bithud)
|
||||||
|
auto cheat_text = Resource::Cache::get()->getText("8bithud");
|
||||||
|
if (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED) {
|
||||||
|
cheat_text->writeColored(CHEAT_INF_LIVES_X, CHEAT_INF_LIVES_Y, Locale::get()->get("scoreboard.cheat_infinite_lives"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||||
|
}
|
||||||
|
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
|
||||||
|
cheat_text->writeColored(CHEAT_INVINCIBLE_X, CHEAT_INVINCIBLE_Y, Locale::get()->get("scoreboard.cheat_invincibility"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||||
|
}
|
||||||
|
|
||||||
// Deja el renderizador como estaba
|
// Deja el renderizador como estaba
|
||||||
Screen::get()->setRendererSurface(previuos_renderer);
|
Screen::get()->setRendererSurface(previuos_renderer);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class Scoreboard {
|
|||||||
void render(); // Pinta el objeto en pantalla
|
void render(); // Pinta el objeto en pantalla
|
||||||
void update(float delta_time); // Actualiza las variables del objeto
|
void update(float delta_time); // Actualiza las variables del objeto
|
||||||
void setPaused(bool value); // Pone el marcador en modo pausa
|
void setPaused(bool value); // Pone el marcador en modo pausa
|
||||||
|
void refreshPlayerSkin(); // Actualiza el sprite del jugador con la skin actual
|
||||||
auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
|
auto getMinutes() -> int; // Devuelve la cantidad de minutos de juego transcurridos
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -42,7 +43,23 @@ class Scoreboard {
|
|||||||
// Constantes de tiempo
|
// Constantes de tiempo
|
||||||
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; // Duración de cada estado del parpadeo (era 10 frames @ 60fps)
|
static constexpr float ITEMS_COLOR_BLINK_DURATION = 0.333F; // Duración de cada estado del parpadeo (era 10 frames @ 60fps)
|
||||||
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
|
static constexpr float SPRITE_WALK_CYCLE_DURATION = 0.667F; // Duración del ciclo de caminar (era 40 frames @ 60fps)
|
||||||
static constexpr int SPRITE_WALK_FRAMES = 4; // Número de frames de animación
|
|
||||||
|
// Posición de los elementos del marcador (en pixels, Tile::SIZE = 8)
|
||||||
|
static constexpr int LINE1_Y = 8; // Fila superior (1 * Tile::SIZE)
|
||||||
|
static constexpr int LINE2_Y = 24; // Fila inferior (3 * Tile::SIZE)
|
||||||
|
static constexpr int ITEMS_LABEL_X = 8; // "TRESORS PILLATS" / "ITEMS COLLECTED"
|
||||||
|
static constexpr int ITEMS_VALUE_X = 136; // Valor numérico de items
|
||||||
|
static constexpr int TIME_LABEL_X = 160; // "HORA" / "TIME"
|
||||||
|
static constexpr int TIME_VALUE_X = 208; // Valor numérico del tiempo
|
||||||
|
static constexpr int LIVES_START_X = 8; // Primera vida (sprite)
|
||||||
|
static constexpr int LIVES_SPACING = 16; // Separación entre vidas
|
||||||
|
static constexpr int MUSIC_ICON_X = 160; // Icono de música
|
||||||
|
static constexpr int ROOMS_LABEL_X = 176; // "SALES" / "ROOMS"
|
||||||
|
static constexpr int ROOMS_VALUE_X = 224; // Valor numérico de salas
|
||||||
|
static constexpr int CHEAT_INF_LIVES_X = 176; // Indicador "vides inf" / "inf lives"
|
||||||
|
static constexpr int CHEAT_INF_LIVES_Y = 34; // Posición Y del indicador de vidas infinitas
|
||||||
|
static constexpr int CHEAT_INVINCIBLE_X = 231; // Indicador "inv"
|
||||||
|
static constexpr int CHEAT_INVINCIBLE_Y = 34; // Posición Y del indicador de invencibilidad
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida
|
auto getTime() -> ClockData; // Obtiene el tiempo transcurrido de partida
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "core/input/input_types.hpp" // Para BUTTON_TO_STRING, STRING_TO_BUTTON
|
#include "core/input/input_types.hpp" // Para BUTTON_TO_STRING, STRING_TO_BUTTON
|
||||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||||
#include "game/defaults.hpp" // Para GameDefaults::VERSION
|
#include "game/defaults.hpp" // Para GameDefaults::VERSION
|
||||||
|
#include "utils/utils.hpp" // Para toLower
|
||||||
|
|
||||||
namespace Options {
|
namespace Options {
|
||||||
|
|
||||||
@@ -177,24 +178,6 @@ namespace Options {
|
|||||||
{"LEFT_STICK_LEFT", 200},
|
{"LEFT_STICK_LEFT", 200},
|
||||||
{"LEFT_STICK_RIGHT", 201}};
|
{"LEFT_STICK_RIGHT", 201}};
|
||||||
|
|
||||||
// Lista de paletas válidas
|
|
||||||
const std::vector<std::string> VALID_PALETTES = {
|
|
||||||
"black-and-white",
|
|
||||||
"green-phosphor",
|
|
||||||
"island-joy-16",
|
|
||||||
"lost-century",
|
|
||||||
"na16",
|
|
||||||
"orange-screen",
|
|
||||||
"pico-8",
|
|
||||||
"ruzx-spectrum",
|
|
||||||
"ruzx-spectrum-revision-2",
|
|
||||||
"steam-lords",
|
|
||||||
"sweetie-16",
|
|
||||||
"sweetie-16_bona",
|
|
||||||
"zx-spectrum",
|
|
||||||
"zx-spectrum-adjusted",
|
|
||||||
"zxarne-5-2"};
|
|
||||||
|
|
||||||
// Funciones helper de conversión
|
// Funciones helper de conversión
|
||||||
auto filterToString(Screen::Filter filter) -> std::string {
|
auto filterToString(Screen::Filter filter) -> std::string {
|
||||||
auto it = FILTER_TO_STRING.find(filter);
|
auto it = FILTER_TO_STRING.find(filter);
|
||||||
@@ -257,12 +240,6 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto isValidPalette(const std::string& palette) -> bool {
|
|
||||||
std::string lower_palette = palette;
|
|
||||||
std::ranges::transform(lower_palette, lower_palette.begin(), ::tolower);
|
|
||||||
return std::ranges::any_of(VALID_PALETTES, [&lower_palette](const auto& valid) { return valid == lower_palette; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Funciones helper para loadFromFile() ---
|
// --- Funciones helper para loadFromFile() ---
|
||||||
|
|
||||||
// Carga configuración de ventana desde YAML
|
// Carga configuración de ventana desde YAML
|
||||||
@@ -309,20 +286,99 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: carga el campo palette con validación extra
|
// Helper: carga el campo palette; PaletteManager hará el fallback si el nombre no existe
|
||||||
void loadPaletteFromYaml(const fkyaml::node& vid) {
|
void loadPaletteFromYaml(const fkyaml::node& vid) {
|
||||||
if (!vid.contains("palette")) { return; }
|
if (vid.contains("palette")) {
|
||||||
try {
|
try {
|
||||||
auto palette_str = vid["palette"].get_value<std::string>();
|
auto palette_str = vid["palette"].get_value<std::string>();
|
||||||
video.palette = isValidPalette(palette_str) ? palette_str : Defaults::Video::PALETTE_NAME;
|
video.palette = toLower(palette_str);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
video.palette = Defaults::Video::PALETTE_NAME;
|
video.palette = Defaults::Video::PALETTE_NAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vid.contains("palette_sort")) {
|
||||||
|
try {
|
||||||
|
video.palette_sort = toLower(vid["palette_sort"].get_value<std::string>());
|
||||||
|
} catch (...) {
|
||||||
|
video.palette_sort = Defaults::Video::PALETTE_SORT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carga los campos básicos de configuración de video
|
// Helper: carga la sección gpu desde YAML
|
||||||
|
void loadGPUConfigFromYaml(const fkyaml::node& gpu_node) {
|
||||||
|
if (gpu_node.contains("acceleration")) {
|
||||||
|
try {
|
||||||
|
video.gpu.acceleration = gpu_node["acceleration"].get_value<bool>();
|
||||||
|
} catch (...) {
|
||||||
|
video.gpu.acceleration = Defaults::Video::GPU_ACCELERATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gpu_node.contains("preferred_driver")) {
|
||||||
|
try {
|
||||||
|
video.gpu.preferred_driver = gpu_node["preferred_driver"].get_value<std::string>();
|
||||||
|
} catch (...) {
|
||||||
|
video.gpu.preferred_driver = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: carga la sección supersampling desde YAML
|
||||||
|
void loadSupersamplingConfigFromYaml(const fkyaml::node& ss_node) {
|
||||||
|
if (ss_node.contains("enabled")) {
|
||||||
|
try {
|
||||||
|
video.supersampling.enabled = ss_node["enabled"].get_value<bool>();
|
||||||
|
} catch (...) {
|
||||||
|
video.supersampling.enabled = Defaults::Video::SUPERSAMPLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ss_node.contains("linear_upscale")) {
|
||||||
|
try {
|
||||||
|
video.supersampling.linear_upscale = ss_node["linear_upscale"].get_value<bool>();
|
||||||
|
} catch (...) {
|
||||||
|
video.supersampling.linear_upscale = Defaults::Video::LINEAR_UPSCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ss_node.contains("downscale_algo")) {
|
||||||
|
try {
|
||||||
|
video.supersampling.downscale_algo = ss_node["downscale_algo"].get_value<int>();
|
||||||
|
} catch (...) {
|
||||||
|
video.supersampling.downscale_algo = Defaults::Video::DOWNSCALE_ALGO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: carga la sección shader desde YAML
|
||||||
|
void loadShaderConfigFromYaml(const fkyaml::node& sh_node) {
|
||||||
|
if (sh_node.contains("enabled")) {
|
||||||
|
try {
|
||||||
|
video.shader.enabled = sh_node["enabled"].get_value<bool>();
|
||||||
|
} catch (...) {
|
||||||
|
video.shader.enabled = Defaults::Video::SHADER_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sh_node.contains("current_shader")) {
|
||||||
|
try {
|
||||||
|
const std::string s = sh_node["current_shader"].get_value<std::string>();
|
||||||
|
video.shader.current_shader = (s == "crtpi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
||||||
|
} catch (...) {
|
||||||
|
video.shader.current_shader = Rendering::ShaderType::POSTFX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sh_node.contains("current_postfx_preset")) {
|
||||||
|
try {
|
||||||
|
video.shader.current_postfx_preset_name = sh_node["current_postfx_preset"].get_value<std::string>();
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
if (sh_node.contains("current_crtpi_preset")) {
|
||||||
|
try {
|
||||||
|
video.shader.current_crtpi_preset_name = sh_node["current_crtpi_preset"].get_value<std::string>();
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carga los campos básicos de configuración de video (nivel video:)
|
||||||
void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) {
|
void loadBasicVideoFieldsFromYaml(const fkyaml::node& vid) {
|
||||||
// fullscreen (antes era "mode")
|
|
||||||
if (vid.contains("fullscreen")) {
|
if (vid.contains("fullscreen")) {
|
||||||
try {
|
try {
|
||||||
video.fullscreen = vid["fullscreen"].get_value<bool>();
|
video.fullscreen = vid["fullscreen"].get_value<bool>();
|
||||||
@@ -331,7 +387,6 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter (ahora es string)
|
|
||||||
if (vid.contains("filter")) {
|
if (vid.contains("filter")) {
|
||||||
try {
|
try {
|
||||||
auto filter_str = vid["filter"].get_value<std::string>();
|
auto filter_str = vid["filter"].get_value<std::string>();
|
||||||
@@ -341,47 +396,6 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vid.contains("postfx")) {
|
|
||||||
try {
|
|
||||||
video.postfx = vid["postfx"].get_value<bool>();
|
|
||||||
} catch (...) {
|
|
||||||
video.postfx = Defaults::Video::POSTFX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("supersampling")) {
|
|
||||||
try {
|
|
||||||
video.supersampling = vid["supersampling"].get_value<bool>();
|
|
||||||
} catch (...) {
|
|
||||||
video.supersampling = Defaults::Video::SUPERSAMPLING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("current_postfx_preset")) {
|
|
||||||
try {
|
|
||||||
current_postfx_preset = vid["current_postfx_preset"].get_value<int>();
|
|
||||||
} catch (...) {
|
|
||||||
current_postfx_preset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("current_crtpi_preset")) {
|
|
||||||
try {
|
|
||||||
current_crtpi_preset = vid["current_crtpi_preset"].get_value<int>();
|
|
||||||
} catch (...) {
|
|
||||||
current_crtpi_preset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("current_shader")) {
|
|
||||||
try {
|
|
||||||
const std::string s = vid["current_shader"].get_value<std::string>();
|
|
||||||
current_shader = (s == "crtpi") ? Rendering::ShaderType::CRTPI : Rendering::ShaderType::POSTFX;
|
|
||||||
} catch (...) {
|
|
||||||
current_shader = Rendering::ShaderType::POSTFX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("vertical_sync")) {
|
if (vid.contains("vertical_sync")) {
|
||||||
try {
|
try {
|
||||||
video.vertical_sync = vid["vertical_sync"].get_value<bool>();
|
video.vertical_sync = vid["vertical_sync"].get_value<bool>();
|
||||||
@@ -406,30 +420,6 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vid.contains("linear_upscale")) {
|
|
||||||
try {
|
|
||||||
video.linear_upscale = vid["linear_upscale"].get_value<bool>();
|
|
||||||
} catch (...) {
|
|
||||||
video.linear_upscale = Defaults::Video::LINEAR_UPSCALE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("downscale_algo")) {
|
|
||||||
try {
|
|
||||||
video.downscale_algo = vid["downscale_algo"].get_value<int>();
|
|
||||||
} catch (...) {
|
|
||||||
video.downscale_algo = Defaults::Video::DOWNSCALE_ALGO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vid.contains("gpu_preferred_driver")) {
|
|
||||||
try {
|
|
||||||
video.gpu_preferred_driver = vid["gpu_preferred_driver"].get_value<std::string>();
|
|
||||||
} catch (...) {
|
|
||||||
video.gpu_preferred_driver = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadPaletteFromYaml(vid);
|
loadPaletteFromYaml(vid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,10 +429,18 @@ namespace Options {
|
|||||||
const auto& vid = yaml["video"];
|
const auto& vid = yaml["video"];
|
||||||
loadBasicVideoFieldsFromYaml(vid);
|
loadBasicVideoFieldsFromYaml(vid);
|
||||||
|
|
||||||
// Lee border
|
|
||||||
if (vid.contains("border")) {
|
if (vid.contains("border")) {
|
||||||
loadBorderConfigFromYaml(vid["border"]);
|
loadBorderConfigFromYaml(vid["border"]);
|
||||||
}
|
}
|
||||||
|
if (vid.contains("gpu")) {
|
||||||
|
loadGPUConfigFromYaml(vid["gpu"]);
|
||||||
|
}
|
||||||
|
if (vid.contains("supersampling")) {
|
||||||
|
loadSupersamplingConfigFromYaml(vid["supersampling"]);
|
||||||
|
}
|
||||||
|
if (vid.contains("shader")) {
|
||||||
|
loadShaderConfigFromYaml(vid["shader"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,12 +518,19 @@ namespace Options {
|
|||||||
const auto& player_node = yaml["player"];
|
const auto& player_node = yaml["player"];
|
||||||
if (player_node.contains("skin")) {
|
if (player_node.contains("skin")) {
|
||||||
try {
|
try {
|
||||||
int skin = player_node["skin"].get_value<int>();
|
game.player_skin = player_node["skin"].get_value<std::string>();
|
||||||
game.player_skin = (skin == 2) ? 2 : Defaults::Game::Player::SKIN;
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
game.player_skin = Defaults::Game::Player::SKIN;
|
game.player_skin = Defaults::Game::Player::SKIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (player_node.contains("color")) {
|
||||||
|
try {
|
||||||
|
int color = player_node["color"].get_value<int>();
|
||||||
|
game.player_color = (color >= 0 && color <= 15) ? color : Defaults::Game::Player::COLOR;
|
||||||
|
} catch (...) {
|
||||||
|
game.player_color = Defaults::Game::Player::COLOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,6 +686,25 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper: retorna el nombre del preset PostFX actual (para guardar en config)
|
||||||
|
auto currentPostFXPresetName() -> std::string {
|
||||||
|
const auto idx = static_cast<size_t>(video.shader.current_postfx_preset);
|
||||||
|
if (idx < postfx_presets.size()) {
|
||||||
|
return postfx_presets[idx].name;
|
||||||
|
}
|
||||||
|
// Presets no cargados aún: devolver el nombre almacenado del config
|
||||||
|
return video.shader.current_postfx_preset_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: retorna el nombre del preset CrtPi actual (para guardar en config)
|
||||||
|
auto currentCrtPiPresetName() -> std::string {
|
||||||
|
const auto idx = static_cast<size_t>(video.shader.current_crtpi_preset);
|
||||||
|
if (idx < crtpi_presets.size()) {
|
||||||
|
return crtpi_presets[idx].name;
|
||||||
|
}
|
||||||
|
return video.shader.current_crtpi_preset_name;
|
||||||
|
}
|
||||||
|
|
||||||
// Guarda las opciones al fichero configurado
|
// Guarda las opciones al fichero configurado
|
||||||
auto saveToFile() -> bool {
|
auto saveToFile() -> bool {
|
||||||
// Abre el fichero para escritura
|
// Abre el fichero para escritura
|
||||||
@@ -727,23 +751,28 @@ namespace Options {
|
|||||||
file << "# VIDEO \n";
|
file << "# VIDEO \n";
|
||||||
file << "video:\n";
|
file << "video:\n";
|
||||||
file << " fullscreen: " << (video.fullscreen ? "true" : "false") << "\n";
|
file << " fullscreen: " << (video.fullscreen ? "true" : "false") << "\n";
|
||||||
file << " filter: " << filterToString(video.filter) << " # filter: nearest (pixel perfect) | linear (smooth)\n";
|
|
||||||
file << " postfx: " << (video.postfx ? "true" : "false") << "\n";
|
|
||||||
file << " supersampling: " << (video.supersampling ? "true" : "false") << "\n";
|
|
||||||
file << " current_postfx_preset: " << current_postfx_preset << "\n";
|
|
||||||
file << " current_crtpi_preset: " << current_crtpi_preset << "\n";
|
|
||||||
file << " current_shader: " << (current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx") << "\n";
|
|
||||||
file << " vertical_sync: " << (video.vertical_sync ? "true" : "false") << "\n";
|
file << " vertical_sync: " << (video.vertical_sync ? "true" : "false") << "\n";
|
||||||
file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n";
|
file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n";
|
||||||
file << " keep_aspect: " << (video.keep_aspect ? "true" : "false") << "\n";
|
file << " keep_aspect: " << (video.keep_aspect ? "true" : "false") << "\n";
|
||||||
file << " linear_upscale: " << (video.linear_upscale ? "true" : "false") << "\n";
|
file << " filter: " << filterToString(video.filter) << " # filter: nearest (pixel perfect) | linear (smooth)\n";
|
||||||
file << " downscale_algo: " << video.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n";
|
|
||||||
file << " gpu_preferred_driver: \"" << video.gpu_preferred_driver << "\" # GPU driver (empty = auto)\n";
|
|
||||||
file << " palette: " << video.palette << "\n";
|
file << " palette: " << video.palette << "\n";
|
||||||
|
file << " palette_sort: " << video.palette_sort << "\n";
|
||||||
file << " border:\n";
|
file << " border:\n";
|
||||||
file << " enabled: " << (video.border.enabled ? "true" : "false") << "\n";
|
file << " enabled: " << (video.border.enabled ? "true" : "false") << "\n";
|
||||||
file << " width: " << video.border.width << "\n";
|
file << " width: " << video.border.width << "\n";
|
||||||
file << " height: " << video.border.height << "\n";
|
file << " height: " << video.border.height << "\n";
|
||||||
|
file << " gpu:\n";
|
||||||
|
file << " acceleration: " << (video.gpu.acceleration ? "true" : "false") << " # Usar aceleración hardware GPU (false = SDL fallback)\n";
|
||||||
|
file << " preferred_driver: \"" << video.gpu.preferred_driver << "\" # Driver GPU específico (empty = auto, aplica solo si gpu_acceleration: true)\n";
|
||||||
|
file << " supersampling:\n";
|
||||||
|
file << " enabled: " << (video.supersampling.enabled ? "true" : "false") << "\n";
|
||||||
|
file << " linear_upscale: " << (video.supersampling.linear_upscale ? "true" : "false") << "\n";
|
||||||
|
file << " downscale_algo: " << video.supersampling.downscale_algo << " # 0=bilinear, 1=Lanczos2, 2=Lanczos3\n";
|
||||||
|
file << " shader:\n";
|
||||||
|
file << " enabled: " << (video.shader.enabled ? "true" : "false") << "\n";
|
||||||
|
file << " current_shader: " << (video.shader.current_shader == Rendering::ShaderType::CRTPI ? "crtpi" : "postfx") << "\n";
|
||||||
|
file << " current_postfx_preset: " << currentPostFXPresetName() << "\n";
|
||||||
|
file << " current_crtpi_preset: " << currentCrtPiPresetName() << "\n";
|
||||||
file << "\n";
|
file << "\n";
|
||||||
|
|
||||||
// KEYBOARD CONTROLS
|
// KEYBOARD CONTROLS
|
||||||
@@ -765,7 +794,8 @@ namespace Options {
|
|||||||
file << "\n";
|
file << "\n";
|
||||||
file << "# PLAYER\n";
|
file << "# PLAYER\n";
|
||||||
file << "player:\n";
|
file << "player:\n";
|
||||||
file << " skin: " << game.player_skin << "\n";
|
file << " skin: \"" << game.player_skin << "\"\n";
|
||||||
|
file << " color: " << game.player_color << "\n";
|
||||||
file << "\n";
|
file << "\n";
|
||||||
|
|
||||||
file << "# KIOSK MODE\n";
|
file << "# KIOSK MODE\n";
|
||||||
@@ -787,6 +817,40 @@ namespace Options {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resuelve el nombre del preset PostFX a índice dentro del vector de presets
|
||||||
|
void resolvePostFXPresetName() {
|
||||||
|
const auto& name = video.shader.current_postfx_preset_name;
|
||||||
|
if (name.empty()) {
|
||||||
|
video.shader.current_postfx_preset = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < static_cast<int>(postfx_presets.size()); ++i) {
|
||||||
|
if (postfx_presets[static_cast<size_t>(i)].name == name) {
|
||||||
|
video.shader.current_postfx_preset = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "PostFX preset '" << name << "' not found, defaulting to first preset\n";
|
||||||
|
video.shader.current_postfx_preset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resuelve el nombre del preset CrtPi a índice dentro del vector de presets
|
||||||
|
void resolveCrtPiPresetName() {
|
||||||
|
const auto& name = video.shader.current_crtpi_preset_name;
|
||||||
|
if (name.empty()) {
|
||||||
|
video.shader.current_crtpi_preset = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < static_cast<int>(crtpi_presets.size()); ++i) {
|
||||||
|
if (crtpi_presets[static_cast<size_t>(i)].name == name) {
|
||||||
|
video.shader.current_crtpi_preset = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "CrtPi preset '" << name << "' not found, defaulting to first preset\n";
|
||||||
|
video.shader.current_crtpi_preset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Establece la ruta del fichero de PostFX
|
// Establece la ruta del fichero de PostFX
|
||||||
void setPostFXFile(const std::string& path) {
|
void setPostFXFile(const std::string& path) {
|
||||||
postfx_file_path = path;
|
postfx_file_path = path;
|
||||||
@@ -838,14 +902,11 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preservar el índice cargado desde config.yaml; clampar al rango válido.
|
// Resolver el nombre del preset a índice
|
||||||
if (!postfx_presets.empty()) {
|
if (!postfx_presets.empty()) {
|
||||||
current_postfx_preset = std::clamp(
|
resolvePostFXPresetName();
|
||||||
current_postfx_preset,
|
|
||||||
0,
|
|
||||||
static_cast<int>(postfx_presets.size()) - 1);
|
|
||||||
} else {
|
} else {
|
||||||
current_postfx_preset = 0;
|
video.shader.current_postfx_preset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "PostFX file loaded: " << postfx_presets.size() << " preset(s)\n";
|
std::cout << "PostFX file loaded: " << postfx_presets.size() << " preset(s)\n";
|
||||||
@@ -950,7 +1011,7 @@ namespace Options {
|
|||||||
postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F});
|
postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F});
|
||||||
postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 0.0F});
|
postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 0.0F});
|
||||||
postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F});
|
postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F});
|
||||||
current_postfx_preset = 0;
|
video.shader.current_postfx_preset = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -981,7 +1042,7 @@ namespace Options {
|
|||||||
crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false});
|
crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false});
|
||||||
crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true});
|
crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true});
|
||||||
crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false});
|
crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false});
|
||||||
current_crtpi_preset = 0;
|
video.shader.current_crtpi_preset = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
out << "# JailDoctor's Dilemma - CrtPi Shader Presets\n";
|
out << "# JailDoctor's Dilemma - CrtPi Shader Presets\n";
|
||||||
@@ -1062,7 +1123,7 @@ namespace Options {
|
|||||||
crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false});
|
crtpi_presets.push_back({"CURVED", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, true, false});
|
||||||
crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true});
|
crtpi_presets.push_back({"SHARP", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, false, true, false, true});
|
||||||
crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false});
|
crtpi_presets.push_back({"MINIMAL", 8.0F, 0.05F, 2.0F, 2.4F, 2.2F, 1.00F, 0.0F, 0.0F, 0, true, false, false, false, false});
|
||||||
current_crtpi_preset = 0;
|
video.shader.current_crtpi_preset = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1121,13 +1182,11 @@ namespace Options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolver el nombre del preset a índice
|
||||||
if (!crtpi_presets.empty()) {
|
if (!crtpi_presets.empty()) {
|
||||||
current_crtpi_preset = std::clamp(
|
resolveCrtPiPresetName();
|
||||||
current_crtpi_preset,
|
|
||||||
0,
|
|
||||||
static_cast<int>(crtpi_presets.size()) - 1);
|
|
||||||
} else {
|
} else {
|
||||||
current_crtpi_preset = 0;
|
video.shader.current_crtpi_preset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "CrtPi file loaded: " << crtpi_presets.size() << " preset(s)\n";
|
std::cout << "CrtPi file loaded: " << crtpi_presets.size() << " preset(s)\n";
|
||||||
@@ -1138,7 +1197,7 @@ namespace Options {
|
|||||||
// Cargar defaults en memoria en caso de error
|
// Cargar defaults en memoria en caso de error
|
||||||
crtpi_presets.clear();
|
crtpi_presets.clear();
|
||||||
crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false});
|
crtpi_presets.push_back({"DEFAULT", 6.0F, 0.12F, 3.5F, 2.4F, 2.2F, 0.80F, 0.05F, 0.10F, 2, true, true, true, false, false});
|
||||||
current_crtpi_preset = 0;
|
video.shader.current_crtpi_preset = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,21 +75,43 @@ namespace Options {
|
|||||||
float height{Defaults::Border::HEIGHT}; // Alto del borde
|
float height{Defaults::Border::HEIGHT}; // Alto del borde
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de video
|
// Estructura para las opciones de GPU
|
||||||
struct Video {
|
struct GPU {
|
||||||
bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa
|
bool acceleration{Defaults::Video::GPU_ACCELERATION}; // Usar aceleración GPU; false = path SDL fallback directo
|
||||||
Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen
|
std::string preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque.
|
||||||
bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no
|
};
|
||||||
bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no
|
|
||||||
bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo
|
// Estructura para las opciones de supersampling
|
||||||
bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
|
struct Supersampling {
|
||||||
bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
|
bool enabled{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo
|
||||||
bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false)
|
bool linear_upscale{Defaults::Video::LINEAR_UPSCALE}; // Upscale LINEAR (true) o NEAREST (false)
|
||||||
int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3
|
int downscale_algo{Defaults::Video::DOWNSCALE_ALGO}; // 0=bilinear, 1=Lanczos2, 2=Lanczos3
|
||||||
Border border{}; // Borde de la pantalla
|
};
|
||||||
std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego
|
|
||||||
std::string info; // Información sobre el modo de vídeo
|
// Estructura para las opciones de shader (dentro de Video)
|
||||||
std::string gpu_preferred_driver; // Driver GPU preferido; vacío = auto. Aplica en el próximo arranque.
|
struct ShaderConfig {
|
||||||
|
bool enabled{Defaults::Video::SHADER_ENABLED}; // Indica si se usan shaders de post-procesado
|
||||||
|
Rendering::ShaderType current_shader{Rendering::ShaderType::POSTFX}; // Shader de post-procesado activo
|
||||||
|
std::string current_postfx_preset_name; // Nombre del preset PostFX leído del config
|
||||||
|
std::string current_crtpi_preset_name; // Nombre del preset CrtPi leído del config
|
||||||
|
int current_postfx_preset{0}; // Índice resuelto del preset PostFX
|
||||||
|
int current_crtpi_preset{0}; // Índice resuelto del preset CrtPi
|
||||||
|
};
|
||||||
|
|
||||||
|
// Estructura para las opciones de video
|
||||||
|
struct Video {
|
||||||
|
bool fullscreen{Defaults::Video::FULLSCREEN}; // Contiene el valor del modo de pantalla completa
|
||||||
|
Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen
|
||||||
|
bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no
|
||||||
|
bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
|
||||||
|
bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
|
||||||
|
std::string palette{Defaults::Video::PALETTE_NAME}; // Paleta de colores a usar en el juego
|
||||||
|
std::string palette_sort{Defaults::Video::PALETTE_SORT}; // Modo de ordenación de la paleta (original/luminance/spectrum)
|
||||||
|
std::string info; // Información sobre el modo de vídeo
|
||||||
|
Border border{}; // Borde de la pantalla
|
||||||
|
GPU gpu{}; // Opciones de aceleración GPU
|
||||||
|
Supersampling supersampling{}; // Opciones de supersampling
|
||||||
|
ShaderConfig shader{}; // Opciones de shader post-procesado
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para las opciones de musica
|
// Estructura para las opciones de musica
|
||||||
@@ -114,9 +136,10 @@ namespace Options {
|
|||||||
|
|
||||||
// Estructura para las opciones de juego
|
// Estructura para las opciones de juego
|
||||||
struct Game {
|
struct Game {
|
||||||
float width{Defaults::Canvas::WIDTH}; // Ancho de la resolucion del juego
|
float width{Defaults::Canvas::WIDTH}; // Ancho de la resolucion del juego
|
||||||
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
|
float height{Defaults::Canvas::HEIGHT}; // Alto de la resolucion del juego
|
||||||
int player_skin{Defaults::Game::Player::SKIN}; // Skin del jugador (1=normal, 2=alternativa)
|
std::string player_skin{Defaults::Game::Player::SKIN}; // Skin del jugador ("default" o nombre de enemigo)
|
||||||
|
int player_color{Defaults::Game::Player::COLOR}; // Color del jugador (-1 = automático, 0-15 = color fijo)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para un preset de PostFX
|
// Estructura para un preset de PostFX
|
||||||
@@ -171,17 +194,12 @@ namespace Options {
|
|||||||
|
|
||||||
// --- Variables PostFX ---
|
// --- Variables PostFX ---
|
||||||
inline std::vector<PostFXPreset> postfx_presets{}; // Lista de presets de PostFX
|
inline std::vector<PostFXPreset> postfx_presets{}; // Lista de presets de PostFX
|
||||||
inline int current_postfx_preset{0}; // Índice del preset de PostFX actual
|
|
||||||
inline std::string postfx_file_path{}; // Ruta del fichero postfx.yaml
|
inline std::string postfx_file_path{}; // Ruta del fichero postfx.yaml
|
||||||
|
|
||||||
// --- Variables CrtPi ---
|
// --- Variables CrtPi ---
|
||||||
inline std::vector<CrtPiPreset> crtpi_presets{}; // Lista de presets del shader CRT-Pi
|
inline std::vector<CrtPiPreset> crtpi_presets{}; // Lista de presets del shader CRT-Pi
|
||||||
inline int current_crtpi_preset{0}; // Índice del preset CRT-Pi actual
|
|
||||||
inline std::string crtpi_file_path{}; // Ruta del fichero crtpi.yaml
|
inline std::string crtpi_file_path{}; // Ruta del fichero crtpi.yaml
|
||||||
|
|
||||||
// --- Shader activo ---
|
|
||||||
inline Rendering::ShaderType current_shader{Rendering::ShaderType::POSTFX}; // Shader de post-procesado activo
|
|
||||||
|
|
||||||
// --- Funciones públicas ---
|
// --- Funciones públicas ---
|
||||||
void setConfigFile(const std::string& path); // Establece la ruta del fichero de configuración
|
void setConfigFile(const std::string& path); // Establece la ruta del fichero de configuración
|
||||||
auto loadFromFile() -> bool; // Carga las opciones desde el fichero configurado
|
auto loadFromFile() -> bool; // Carga las opciones desde el fichero configurado
|
||||||
@@ -192,4 +210,7 @@ namespace Options {
|
|||||||
void setCrtPiFile(const std::string& path); // Establece la ruta del fichero de CrtPi
|
void setCrtPiFile(const std::string& path); // Establece la ruta del fichero de CrtPi
|
||||||
auto loadCrtPiFromFile() -> bool; // Carga los presets de CrtPi desde el fichero (crea defaults si no existe)
|
auto loadCrtPiFromFile() -> bool; // Carga los presets de CrtPi desde el fichero (crea defaults si no existe)
|
||||||
|
|
||||||
|
void resolvePostFXPresetName(); // Resuelve el nombre del preset PostFX a índice
|
||||||
|
void resolveCrtPiPresetName(); // Resuelve el nombre del preset CrtPi a índice
|
||||||
|
|
||||||
} // namespace Options
|
} // namespace Options
|
||||||
@@ -391,7 +391,7 @@ void Ending2::placeSprites() const {
|
|||||||
const float X = (Options::game.width - sprites_.back()->getWidth()) / 2;
|
const float X = (Options::game.width - sprites_.back()->getWidth()) / 2;
|
||||||
const float Y = sprites_.back()->getPosY() + (sprite_max_height_ * 2);
|
const float Y = sprites_.back()->getPosY() + (sprite_max_height_ * 2);
|
||||||
sprites_.back()->setPos(X, Y);
|
sprites_.back()->setPos(X, Y);
|
||||||
sprites_.back()->setCurrentAnimation("walk");
|
sprites_.back()->setCurrentAnimation("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crea los sprites con las texturas con los textos
|
// Crea los sprites con las texturas con los textos
|
||||||
|
|||||||
@@ -64,11 +64,16 @@ Game::Game(Mode mode)
|
|||||||
Cheevos::get()->enable(!Options::cheats.enabled()); // Deshabilita los logros si hay trucos activados
|
Cheevos::get()->enable(!Options::cheats.enabled()); // Deshabilita los logros si hay trucos activados
|
||||||
Cheevos::get()->clearUnobtainableState();
|
Cheevos::get()->clearUnobtainableState();
|
||||||
|
|
||||||
GameControl::refresh_player_color = [this]() -> void { player_->setColor(); };
|
|
||||||
Console::get()->on_toggle = [this](bool open) { player_->setIgnoreInput(open); };
|
Console::get()->on_toggle = [this](bool open) { player_->setIgnoreInput(open); };
|
||||||
GameControl::change_player_skin = [this](int skin_num) -> void {
|
if (Console::get()->isActive()) { player_->setIgnoreInput(true); }
|
||||||
Options::game.player_skin = skin_num;
|
GameControl::change_player_skin = [this](const std::string& skin_name) -> void {
|
||||||
player_->setSkin(skin_num);
|
Options::game.player_skin = skin_name;
|
||||||
|
player_->setSkin(skin_name);
|
||||||
|
scoreboard_->refreshPlayerSkin();
|
||||||
|
};
|
||||||
|
GameControl::change_player_color = [this](int color) -> void {
|
||||||
|
Options::game.player_color = color;
|
||||||
|
player_->setColor();
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@@ -79,9 +84,17 @@ Game::Game(Mode mode)
|
|||||||
Options::stats.items = count;
|
Options::stats.items = count;
|
||||||
};
|
};
|
||||||
GameControl::toggle_debug_mode = [this]() -> void {
|
GameControl::toggle_debug_mode = [this]() -> void {
|
||||||
|
const bool ENTERING_DEBUG = !Debug::get()->isEnabled();
|
||||||
|
if (ENTERING_DEBUG) {
|
||||||
|
invincible_before_debug_ = (Options::cheats.invincible == Options::Cheat::State::ENABLED);
|
||||||
|
}
|
||||||
Debug::get()->toggleEnabled();
|
Debug::get()->toggleEnabled();
|
||||||
room_->redrawMap();
|
room_->redrawMap();
|
||||||
Options::cheats.invincible = static_cast<Options::Cheat::State>(Debug::get()->isEnabled());
|
if (Debug::get()->isEnabled()) {
|
||||||
|
Options::cheats.invincible = Options::Cheat::State::ENABLED;
|
||||||
|
} else {
|
||||||
|
Options::cheats.invincible = invincible_before_debug_ ? Options::Cheat::State::ENABLED : Options::Cheat::State::DISABLED;
|
||||||
|
}
|
||||||
player_->setColor();
|
player_->setColor();
|
||||||
scoreboard_data_->music = !Debug::get()->isEnabled();
|
scoreboard_data_->music = !Debug::get()->isEnabled();
|
||||||
scoreboard_data_->music ? Audio::get()->resumeMusic() : Audio::get()->pauseMusic();
|
scoreboard_data_->music ? Audio::get()->resumeMusic() : Audio::get()->pauseMusic();
|
||||||
@@ -115,8 +128,8 @@ Game::Game(Mode mode)
|
|||||||
Game::~Game() {
|
Game::~Game() {
|
||||||
ItemTracker::destroy();
|
ItemTracker::destroy();
|
||||||
|
|
||||||
GameControl::refresh_player_color = nullptr;
|
|
||||||
GameControl::change_player_skin = nullptr;
|
GameControl::change_player_skin = nullptr;
|
||||||
|
GameControl::change_player_color = nullptr;
|
||||||
Console::get()->on_toggle = nullptr;
|
Console::get()->on_toggle = nullptr;
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@@ -511,15 +524,24 @@ void Game::handleDebugEvents(const SDL_Event& event) { // NOLINT(readability-co
|
|||||||
Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c11")}, Notifier::Style::CHEEVO, -1, false, "F7"); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Locale::get()->get("achievements.header"), Locale::get()->get("achievements.c11")}, Notifier::Style::CHEEVO, -1, false, "F7"); // NOLINT(readability-static-accessed-through-instance)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_0:
|
case SDLK_0: {
|
||||||
|
const bool ENTERING_DEBUG = !Debug::get()->isEnabled();
|
||||||
|
if (ENTERING_DEBUG) {
|
||||||
|
invincible_before_debug_ = (Options::cheats.invincible == Options::Cheat::State::ENABLED);
|
||||||
|
}
|
||||||
Debug::get()->toggleEnabled();
|
Debug::get()->toggleEnabled();
|
||||||
Notifier::get()->show({Debug::get()->isEnabled() ? Locale::get()->get("game.debug_enabled") : Locale::get()->get("game.debug_disabled")}); // NOLINT(readability-static-accessed-through-instance)
|
Notifier::get()->show({Debug::get()->isEnabled() ? Locale::get()->get("game.debug_enabled") : Locale::get()->get("game.debug_disabled")}); // NOLINT(readability-static-accessed-through-instance)
|
||||||
room_->redrawMap();
|
room_->redrawMap();
|
||||||
Options::cheats.invincible = static_cast<Options::Cheat::State>(Debug::get()->isEnabled());
|
if (Debug::get()->isEnabled()) {
|
||||||
|
Options::cheats.invincible = Options::Cheat::State::ENABLED;
|
||||||
|
} else {
|
||||||
|
Options::cheats.invincible = invincible_before_debug_ ? Options::Cheat::State::ENABLED : Options::Cheat::State::DISABLED;
|
||||||
|
}
|
||||||
player_->setColor();
|
player_->setColor();
|
||||||
scoreboard_data_->music = !Debug::get()->isEnabled();
|
scoreboard_data_->music = !Debug::get()->isEnabled();
|
||||||
scoreboard_data_->music ? Audio::get()->resumeMusic() : Audio::get()->pauseMusic();
|
scoreboard_data_->music ? Audio::get()->resumeMusic() : Audio::get()->pauseMusic();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -637,6 +659,9 @@ auto Game::changeRoom(const std::string& room_path) -> bool {
|
|||||||
// Pasa la nueva habitación al jugador
|
// Pasa la nueva habitación al jugador
|
||||||
player_->setRoom(room_);
|
player_->setRoom(room_);
|
||||||
|
|
||||||
|
// Recalcula el color del jugador (evita coincidir con el fondo)
|
||||||
|
player_->setColor();
|
||||||
|
|
||||||
// Cambia la habitación actual
|
// Cambia la habitación actual
|
||||||
current_room_ = room_path;
|
current_room_ = room_path;
|
||||||
|
|
||||||
@@ -882,9 +907,11 @@ void Game::checkEndGameCheevos() { // NOLINT(readability-convert-member-functio
|
|||||||
|
|
||||||
// Inicializa al jugador
|
// Inicializa al jugador
|
||||||
void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) { // NOLINT(readability-convert-member-functions-to-static)
|
void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room) { // NOLINT(readability-convert-member-functions-to-static)
|
||||||
std::string player_animations = (Options::game.player_skin == 2) ? "player2.yaml" : "player.yaml";
|
const bool IGNORE_INPUT = player_ != nullptr && player_->getIgnoreInput();
|
||||||
|
std::string player_animations = Player::skinToAnimationPath(Options::game.player_skin);
|
||||||
const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = player_animations, .room = std::move(room)};
|
const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = player_animations, .room = std::move(room)};
|
||||||
player_ = std::make_shared<Player>(PLAYER);
|
player_ = std::make_shared<Player>(PLAYER);
|
||||||
|
if (IGNORE_INPUT) { player_->setIgnoreInput(true); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crea la textura para poner el nombre de la habitación
|
// Crea la textura para poner el nombre de la habitación
|
||||||
|
|||||||
@@ -130,5 +130,7 @@ class Game {
|
|||||||
// Variables de debug para arrastre con ratón
|
// Variables de debug para arrastre con ratón
|
||||||
bool debug_dragging_player_{false}; // Indica si estamos arrastrando al jugador con el ratón
|
bool debug_dragging_player_{false}; // Indica si estamos arrastrando al jugador con el ratón
|
||||||
float debug_drag_speed_{0.0F}; // Velocidad actual del arrastre (ease-in)
|
float debug_drag_speed_{0.0F}; // Velocidad actual del arrastre (ease-in)
|
||||||
|
// Estado previo de invencibilidad antes de entrar en modo debug
|
||||||
|
bool invincible_before_debug_{false};
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,9 @@
|
|||||||
#include <functional> // Para function
|
#include <functional> // Para function
|
||||||
#include <memory> // Para shared_ptr
|
#include <memory> // Para shared_ptr
|
||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
#include "game/ui/console_commands.hpp" // Para CommandRegistry
|
||||||
|
|
||||||
class Surface;
|
class Surface;
|
||||||
class Sprite;
|
class Sprite;
|
||||||
@@ -44,15 +47,16 @@ class Console {
|
|||||||
static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK
|
static constexpr Uint8 BG_COLOR = 0; // PaletteColor::BLACK
|
||||||
static constexpr Uint8 BORDER_COLOR = 9; // PaletteColor::BRIGHT_GREEN
|
static constexpr Uint8 BORDER_COLOR = 9; // PaletteColor::BRIGHT_GREEN
|
||||||
static constexpr Uint8 MSG_COLOR = 8; // PaletteColor::GREEN
|
static constexpr Uint8 MSG_COLOR = 8; // PaletteColor::GREEN
|
||||||
static constexpr float SLIDE_SPEED = 120.0F;
|
static constexpr float SLIDE_SPEED = 180.0F;
|
||||||
|
|
||||||
// Constantes de consola
|
// Constantes de consola
|
||||||
static constexpr std::string_view CONSOLE_NAME = "JDD Console";
|
static constexpr std::string_view CONSOLE_NAME = "JDD Console";
|
||||||
static constexpr std::string_view CONSOLE_VERSION = "v1.0";
|
static constexpr std::string_view CONSOLE_VERSION = "v2.1";
|
||||||
static constexpr int MAX_LINE_CHARS = 32;
|
static constexpr int MAX_LINE_CHARS = 32;
|
||||||
static constexpr int MAX_HISTORY_SIZE = 20;
|
static constexpr int MAX_HISTORY_SIZE = 20;
|
||||||
static constexpr float CURSOR_ON_TIME = 0.5F;
|
static constexpr float CURSOR_ON_TIME = 0.5F;
|
||||||
static constexpr float CURSOR_OFF_TIME = 0.3F;
|
static constexpr float CURSOR_OFF_TIME = 0.3F;
|
||||||
|
static constexpr float TYPEWRITER_CHAR_DELAY = 0.01F; // segundos entre letra y letra
|
||||||
|
|
||||||
// [SINGLETON]
|
// [SINGLETON]
|
||||||
static Console* console;
|
static Console* console;
|
||||||
@@ -62,9 +66,10 @@ class Console {
|
|||||||
~Console() = default;
|
~Console() = default;
|
||||||
|
|
||||||
// Métodos privados
|
// Métodos privados
|
||||||
void buildSurface(); // Crea la Surface con el aspecto visual
|
void buildSurface(); // Crea la Surface con el aspecto visual
|
||||||
void redrawText(); // Redibuja el texto dinámico (msg + input + cursor)
|
void redrawText(); // Redibuja el texto dinámico (msg + input + cursor)
|
||||||
void processCommand(); // Procesa el comando introducido por el usuario
|
void processCommand(); // Procesa el comando introducido por el usuario
|
||||||
|
[[nodiscard]] auto wrapText(const std::string& text) const -> std::vector<std::string>; // Word-wrap por ancho en píxeles
|
||||||
|
|
||||||
// Objetos de renderizado
|
// Objetos de renderizado
|
||||||
std::shared_ptr<Text> text_;
|
std::shared_ptr<Text> text_;
|
||||||
@@ -77,13 +82,28 @@ class Console {
|
|||||||
float height_{0.0F}; // Altura del panel
|
float height_{0.0F}; // Altura del panel
|
||||||
|
|
||||||
// Estado de la entrada de texto
|
// Estado de la entrada de texto
|
||||||
std::string msg_line_; // inicializado en constructor con CONSOLE_NAME + CONSOLE_VERSION
|
std::vector<std::string> msg_lines_; // Líneas de mensaje (1 o más)
|
||||||
std::string input_line_;
|
std::string input_line_;
|
||||||
float cursor_timer_{0.0F};
|
float cursor_timer_{0.0F};
|
||||||
bool cursor_visible_{true};
|
bool cursor_visible_{true};
|
||||||
|
|
||||||
|
// Efecto typewriter
|
||||||
|
int typewriter_chars_{0}; // Caracteres de msg_lines_ actualmente visibles
|
||||||
|
float typewriter_timer_{0.0F};
|
||||||
|
|
||||||
|
// Animación de altura dinámica
|
||||||
|
float target_height_{0.0F}; // Altura objetivo (según número de líneas de mensaje)
|
||||||
|
int notifier_offset_applied_{0}; // Acumulador del offset enviado al Notifier
|
||||||
|
|
||||||
// Historial de comandos (navegable con flechas arriba/abajo)
|
// Historial de comandos (navegable con flechas arriba/abajo)
|
||||||
std::deque<std::string> history_;
|
std::deque<std::string> history_;
|
||||||
int history_index_{-1}; // -1 = en la entrada actual (presente)
|
int history_index_{-1}; // -1 = en la entrada actual (presente)
|
||||||
std::string saved_input_; // guarda input_line_ al empezar a navegar
|
std::string saved_input_; // guarda input_line_ al empezar a navegar
|
||||||
|
|
||||||
|
// Estado de autocompletado (TAB)
|
||||||
|
std::vector<std::string> tab_matches_; // Comandos que coinciden con el prefijo actual
|
||||||
|
int tab_index_{-1}; // Índice actual en tab_matches_
|
||||||
|
|
||||||
|
// Registro de comandos (metadatos YAML + handlers C++)
|
||||||
|
CommandRegistry registry_;
|
||||||
};
|
};
|
||||||
|
|||||||
1049
source/game/ui/console_commands.cpp
Normal file
1049
source/game/ui/console_commands.cpp
Normal file
File diff suppressed because it is too large
Load Diff
56
source/game/ui/console_commands.hpp
Normal file
56
source/game/ui/console_commands.hpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional> // Para function
|
||||||
|
#include <string> // Para string
|
||||||
|
#include <unordered_map> // Para unordered_map
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
// Definición de un comando de consola (metadatos cargados desde YAML)
|
||||||
|
struct CommandDef {
|
||||||
|
std::string keyword;
|
||||||
|
std::string handler_id;
|
||||||
|
std::string category;
|
||||||
|
std::string description;
|
||||||
|
std::string usage;
|
||||||
|
bool instant{false};
|
||||||
|
bool hidden{false};
|
||||||
|
bool debug_only{false};
|
||||||
|
bool help_hidden{false};
|
||||||
|
bool dynamic_completions{false};
|
||||||
|
std::unordered_map<std::string, std::vector<std::string>> completions;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tipo de función handler para comandos
|
||||||
|
using CommandHandler = std::function<std::string(const std::vector<std::string>& args)>;
|
||||||
|
|
||||||
|
// Proveedor de completions dinámicas: devuelve las opciones para TAB en UPPERCASE
|
||||||
|
using DynamicCompletionProvider = std::function<std::vector<std::string>()>;
|
||||||
|
|
||||||
|
// Registro de comandos: une metadatos YAML con handlers C++
|
||||||
|
class CommandRegistry {
|
||||||
|
public:
|
||||||
|
// Carga los metadatos de comandos desde un archivo YAML y registra los handlers
|
||||||
|
void load(const std::string& yaml_path);
|
||||||
|
|
||||||
|
// Búsqueda y ejecución
|
||||||
|
[[nodiscard]] auto findCommand(const std::string& keyword) const -> const CommandDef*;
|
||||||
|
auto execute(const std::string& keyword, const std::vector<std::string>& args) const -> std::string;
|
||||||
|
|
||||||
|
// Generación de ayuda (auto-generada desde los metadatos)
|
||||||
|
[[nodiscard]] auto generateTerminalHelp() const -> std::string;
|
||||||
|
[[nodiscard]] auto generateConsoleHelp() const -> std::string;
|
||||||
|
|
||||||
|
// TAB completion
|
||||||
|
// Devuelve las opciones de completado para un path dado (ej: "SHADER", "SHADER PRESET")
|
||||||
|
// Combina completions estáticas del YAML con dinámicas registradas en C++
|
||||||
|
[[nodiscard]] auto getCompletions(const std::string& path) const -> std::vector<std::string>;
|
||||||
|
[[nodiscard]] auto getVisibleKeywords() const -> std::vector<std::string>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<CommandDef> commands_;
|
||||||
|
std::unordered_map<std::string, CommandHandler> handlers_;
|
||||||
|
std::unordered_map<std::string, std::vector<std::string>> completions_map_;
|
||||||
|
std::unordered_map<std::string, DynamicCompletionProvider> dynamic_providers_;
|
||||||
|
|
||||||
|
void registerHandlers();
|
||||||
|
};
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace Texts {
|
namespace Texts {
|
||||||
constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner";
|
constexpr const char* WINDOW_CAPTION = "© 2022 JailDoctor's Dilemma — JailDesigner";
|
||||||
constexpr const char* COPYRIGHT = "@2022 JailDesigner";
|
constexpr const char* COPYRIGHT = "@2022 JailDesigner";
|
||||||
constexpr const char* VERSION = "1.10"; // Versión por defecto
|
constexpr const char* VERSION = "1.12"; // Versión por defecto
|
||||||
} // namespace Texts
|
} // namespace Texts
|
||||||
|
|
||||||
// Tamaño de bloque
|
// Tamaño de bloque
|
||||||
|
|||||||
@@ -414,6 +414,13 @@ auto toUpper(const std::string& str) -> std::string {
|
|||||||
return upper_str;
|
return upper_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convierte guiones a espacios ("crt-live" → "crt live")
|
||||||
|
auto prettyName(const std::string& str) -> std::string {
|
||||||
|
std::string result = str;
|
||||||
|
std::ranges::replace(result, '-', ' ');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Obtiene el nombre de un fichero a partir de una ruta completa
|
// Obtiene el nombre de un fichero a partir de una ruta completa
|
||||||
auto getFileName(const std::string& path) -> std::string {
|
auto getFileName(const std::string& path) -> std::string {
|
||||||
return std::filesystem::path(path).filename().string();
|
return std::filesystem::path(path).filename().string();
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ auto stringToBool(const std::string& str) -> bool; // Strin
|
|||||||
auto boolToString(bool value) -> std::string; // Bool a string (1/0)
|
auto boolToString(bool value) -> std::string; // Bool a string (1/0)
|
||||||
auto toLower(const std::string& str) -> std::string; // String a minúsculas
|
auto toLower(const std::string& str) -> std::string; // String a minúsculas
|
||||||
auto toUpper(const std::string& str) -> std::string; // String a mayúsculas
|
auto toUpper(const std::string& str) -> std::string; // String a mayúsculas
|
||||||
|
auto prettyName(const std::string& str) -> std::string; // Guiones a espacios ("crt-live" → "crt live")
|
||||||
|
|
||||||
// OPERACIONES CON STRINGS
|
// OPERACIONES CON STRINGS
|
||||||
auto stringInVector(const std::vector<std::string>& vec, const std::string& str) -> bool; // Busca string en vector
|
auto stringInVector(const std::vector<std::string>& vec, const std::string& str) -> bool; // Busca string en vector
|
||||||
|
|||||||
125
tools/sort_palette/sort_palette.py
Normal file
125
tools/sort_palette/sort_palette.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import sys
|
||||||
|
import math
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Utilidades de color
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
def luminosidad(rgb):
|
||||||
|
r, g, b = rgb
|
||||||
|
return 0.2126*r + 0.7152*g + 0.0722*b
|
||||||
|
|
||||||
|
def distancia_rgb(c1, c2):
|
||||||
|
return math.sqrt(
|
||||||
|
(c1[0] - c2[0])**2 +
|
||||||
|
(c1[1] - c2[1])**2 +
|
||||||
|
(c1[2] - c2[2])**2
|
||||||
|
)
|
||||||
|
|
||||||
|
# Paleta ZX Spectrum
|
||||||
|
PALETA_SPECTRUM = [
|
||||||
|
(0, 0, 0),
|
||||||
|
(0, 0, 0),
|
||||||
|
(0, 0, 216),
|
||||||
|
(0, 0, 255),
|
||||||
|
(216, 0, 0),
|
||||||
|
(255, 0, 0),
|
||||||
|
(216, 0, 216),
|
||||||
|
(255, 0, 255),
|
||||||
|
(0, 216, 0),
|
||||||
|
(0, 255, 0),
|
||||||
|
(0, 216, 216),
|
||||||
|
(0, 255, 255),
|
||||||
|
(216, 216, 0),
|
||||||
|
(255, 255, 0),
|
||||||
|
(216, 216, 216),
|
||||||
|
(255, 255, 255),
|
||||||
|
]
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Lectura / escritura JASC-PAL
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
def leer_paleta_jasc(ruta):
|
||||||
|
with open(ruta, "r") as f:
|
||||||
|
lineas = [l.strip() for l in f.readlines()]
|
||||||
|
|
||||||
|
if lineas[0] != "JASC-PAL":
|
||||||
|
raise ValueError("El fichero no es un JASC-PAL válido")
|
||||||
|
|
||||||
|
num_colores = int(lineas[2])
|
||||||
|
colores = []
|
||||||
|
|
||||||
|
for i in range(num_colores):
|
||||||
|
r, g, b = map(int, lineas[3 + i].split())
|
||||||
|
colores.append((r, g, b))
|
||||||
|
|
||||||
|
return colores
|
||||||
|
|
||||||
|
def guardar_paleta_jasc(ruta, colores):
|
||||||
|
with open(ruta, "w") as f:
|
||||||
|
f.write("JASC-PAL\n")
|
||||||
|
f.write("0100\n")
|
||||||
|
f.write(f"{len(colores)}\n")
|
||||||
|
for r, g, b in colores:
|
||||||
|
f.write(f"{r} {g} {b}\n")
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Métodos de ordenación
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
def ordenar_por_luminosidad(colores):
|
||||||
|
return sorted(colores, key=luminosidad)
|
||||||
|
|
||||||
|
def ordenar_por_similitud_spectrum(colores):
|
||||||
|
colores_disponibles = colores.copy()
|
||||||
|
resultado = []
|
||||||
|
|
||||||
|
for ref in PALETA_SPECTRUM:
|
||||||
|
mejor = min(colores_disponibles, key=lambda c: distancia_rgb(c, ref))
|
||||||
|
resultado.append(mejor)
|
||||||
|
colores_disponibles.remove(mejor)
|
||||||
|
|
||||||
|
return resultado
|
||||||
|
|
||||||
|
# ------------------------------
|
||||||
|
# Main
|
||||||
|
# ------------------------------
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 4:
|
||||||
|
print("Uso: python ordenar_paleta.py entrada.pal salida.pal [luminosidad|spectrum]")
|
||||||
|
return
|
||||||
|
|
||||||
|
entrada = sys.argv[1]
|
||||||
|
salida = sys.argv[2]
|
||||||
|
modo = sys.argv[3].lower()
|
||||||
|
|
||||||
|
colores = leer_paleta_jasc(entrada)
|
||||||
|
|
||||||
|
if modo == "luminosidad":
|
||||||
|
colores_ordenados = ordenar_por_luminosidad(colores)
|
||||||
|
elif modo == "spectrum":
|
||||||
|
colores_ordenados = ordenar_por_similitud_spectrum(colores)
|
||||||
|
else:
|
||||||
|
print(f"Modo desconocido: {modo}")
|
||||||
|
print("Modos disponibles: luminosidad, spectrum")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Si salida == entrada, sobrescribimos de forma segura
|
||||||
|
if entrada == salida:
|
||||||
|
# Guardamos primero en un temporal para evitar corrupción si algo falla
|
||||||
|
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
||||||
|
temp_path = tmp.name
|
||||||
|
guardar_paleta_jasc(temp_path, colores_ordenados)
|
||||||
|
os.replace(temp_path, entrada)
|
||||||
|
print(f"Paleta sobrescrita ({modo}) en {entrada}")
|
||||||
|
else:
|
||||||
|
guardar_paleta_jasc(salida, colores_ordenados)
|
||||||
|
print(f"Paleta ordenada ({modo}) guardada en {salida}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user