3 Commits

12 changed files with 61 additions and 21 deletions

2
.gitignore vendored
View File

@@ -12,7 +12,6 @@ vibe3_physics.exe
*.lib *.lib
*.so *.so
*.dylib *.dylib
*.dll
# Archivos de compilación y enlazado # Archivos de compilación y enlazado
*.d *.d
@@ -26,6 +25,7 @@ Build/
BUILD/ BUILD/
cmake-build-*/ cmake-build-*/
.cmake/ .cmake/
.cache/
# Archivos generados por CMake # Archivos generados por CMake
CMakeFiles/ CMakeFiles/

View File

@@ -159,7 +159,7 @@ windows_release: force_resource_pack
# Copia los ficheros que estan en la raíz del proyecto # Copia los ficheros que estan en la raíz del proyecto
@copy /Y "LICENSE" "$(RELEASE_FOLDER)\" >nul 2>&1 || echo LICENSE not found (optional) @copy /Y "LICENSE" "$(RELEASE_FOLDER)\" >nul 2>&1 || echo LICENSE not found (optional)
@copy /Y "README.md" "$(RELEASE_FOLDER)\" >nul @copy /Y "README.md" "$(RELEASE_FOLDER)\" >nul
@copy /Y release\*.dll "$(RELEASE_FOLDER)\" >nul 2>&1 || echo DLLs copied successfully @copy /Y release\dll\*.dll "$(RELEASE_FOLDER)\" >nul 2>&1 || echo DLLs copied successfully
# Compila # Compila
@windres release/vibe3.rc -O coff -o $(RESOURCE_FILE) @windres release/vibe3.rc -O coff -o $(RESOURCE_FILE)

Binary file not shown.

View File

@@ -32,6 +32,7 @@ constexpr Uint64 NOTIFICATION_FADE_TIME = 200; // Duración animación salida
constexpr float NOTIFICATION_BG_ALPHA = 0.7f; // Opacidad fondo semitransparente (0.0-1.0) constexpr float NOTIFICATION_BG_ALPHA = 0.7f; // Opacidad fondo semitransparente (0.0-1.0)
constexpr int NOTIFICATION_PADDING = 10; // Padding interno del fondo (píxeles físicos) constexpr int NOTIFICATION_PADDING = 10; // Padding interno del fondo (píxeles físicos)
constexpr int NOTIFICATION_TOP_MARGIN = 20; // Margen superior desde borde pantalla (píxeles físicos) constexpr int NOTIFICATION_TOP_MARGIN = 20; // Margen superior desde borde pantalla (píxeles físicos)
constexpr char KIOSK_NOTIFICATION_TEXT[] = "MODO KIOSKO";
// Configuración de pérdida aleatoria en rebotes // Configuración de pérdida aleatoria en rebotes
constexpr float BASE_BOUNCE_COEFFICIENT = 0.75f; // Coeficiente base IGUAL para todas las pelotas constexpr float BASE_BOUNCE_COEFFICIENT = 0.75f; // Coeficiente base IGUAL para todas las pelotas

View File

@@ -282,6 +282,13 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen, AppMod
// No es crítico, continuar sin logo // No es crítico, continuar sin logo
app_logo_.reset(); app_logo_.reset();
} }
// Precalentar caché: shapes PNG (evitar I/O en primera activación de PNG_SHAPE)
{
unsigned char* tmp = nullptr; size_t tmp_size = 0;
ResourceManager::loadResource("shapes/jailgames.png", tmp, tmp_size);
delete[] tmp;
}
} }
return success; return success;

View File

@@ -71,6 +71,13 @@ class Engine {
void toggleRealFullscreen(); void toggleRealFullscreen();
void toggleIntegerScaling(); void toggleIntegerScaling();
// Modo kiosko
void setKioskMode(bool enabled) { kiosk_mode_ = enabled; }
bool isKioskMode() const { return kiosk_mode_; }
// Notificaciones (público para InputHandler)
void showNotificationForAction(const std::string& text);
// Modos de aplicación (DEMO/LOGO) // Modos de aplicación (DEMO/LOGO)
void toggleDemoMode(); void toggleDemoMode();
void toggleDemoLiteMode(); void toggleDemoLiteMode();
@@ -131,6 +138,7 @@ class Engine {
bool vsync_enabled_ = true; bool vsync_enabled_ = true;
bool fullscreen_enabled_ = false; bool fullscreen_enabled_ = false;
bool real_fullscreen_enabled_ = false; bool real_fullscreen_enabled_ = false;
bool kiosk_mode_ = false;
ScalingMode current_scaling_mode_ = ScalingMode::INTEGER; // Modo de escalado actual (F5) ScalingMode current_scaling_mode_ = ScalingMode::INTEGER; // Modo de escalado actual (F5)
// Resolución base (configurada por CLI o default) // Resolución base (configurada por CLI o default)
@@ -204,7 +212,6 @@ class Engine {
void render(); void render();
// Métodos auxiliares privados (llamados por la interfaz pública) // Métodos auxiliares privados (llamados por la interfaz pública)
void showNotificationForAction(const std::string& text); // Mostrar notificación solo en modo MANUAL
// Sistema de cambio de sprites dinámico - Métodos privados // Sistema de cambio de sprites dinámico - Métodos privados
void switchTextureInternal(bool show_notification); // Implementación interna del cambio de textura void switchTextureInternal(bool show_notification); // Implementación interna del cambio de textura

View File

@@ -3,7 +3,8 @@
#include <SDL3/SDL_keycode.h> // for SDL_Keycode #include <SDL3/SDL_keycode.h> // for SDL_Keycode
#include <string> // for std::string, std::to_string #include <string> // for std::string, std::to_string
#include "engine.hpp" // for Engine #include "defines.hpp" // for KIOSK_NOTIFICATION_TEXT
#include "engine.hpp" // for Engine
#include "external/mouse.hpp" // for Mouse namespace #include "external/mouse.hpp" // for Mouse namespace
bool InputHandler::processEvents(Engine& engine) { bool InputHandler::processEvents(Engine& engine) {
@@ -21,6 +22,10 @@ bool InputHandler::processEvents(Engine& engine) {
if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) { if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) {
switch (event.key.key) { switch (event.key.key) {
case SDLK_ESCAPE: case SDLK_ESCAPE:
if (engine.isKioskMode()) {
engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT);
break;
}
return true; // Solicitar salida return true; // Solicitar salida
case SDLK_SPACE: case SDLK_SPACE:
@@ -221,21 +226,21 @@ bool InputHandler::processEvents(Engine& engine) {
// Controles de zoom dinámico (solo si no estamos en fullscreen) // Controles de zoom dinámico (solo si no estamos en fullscreen)
case SDLK_F1: case SDLK_F1:
engine.handleZoomOut(); if (!engine.isKioskMode()) engine.handleZoomOut();
break; break;
case SDLK_F2: case SDLK_F2:
engine.handleZoomIn(); if (!engine.isKioskMode()) engine.handleZoomIn();
break; break;
// Control de pantalla completa // Control de pantalla completa
case SDLK_F3: case SDLK_F3:
engine.toggleFullscreen(); if (!engine.isKioskMode()) engine.toggleFullscreen();
break; break;
// Modo real fullscreen (cambia resolución interna) // Modo real fullscreen (cambia resolución interna)
case SDLK_F4: case SDLK_F4:
engine.toggleRealFullscreen(); if (!engine.isKioskMode()) engine.toggleRealFullscreen();
break; break;
// Toggle escalado entero/estirado (solo en fullscreen F3) // Toggle escalado entero/estirado (solo en fullscreen F3)

View File

@@ -16,6 +16,7 @@ void printHelp() {
std::cout << " -z, --zoom <n> Zoom de ventana (default: 3)\n"; std::cout << " -z, --zoom <n> Zoom de ventana (default: 3)\n";
std::cout << " -f, --fullscreen Modo pantalla completa (F3 - letterbox)\n"; std::cout << " -f, --fullscreen Modo pantalla completa (F3 - letterbox)\n";
std::cout << " -F, --real-fullscreen Modo pantalla completa real (F4 - nativo)\n"; std::cout << " -F, --real-fullscreen Modo pantalla completa real (F4 - nativo)\n";
std::cout << " -k, --kiosk Modo kiosko (F4 fijo, sin ESC, sin zoom)\n";
std::cout << " -m, --mode <mode> Modo inicial: sandbox, demo, demo-lite, logo (default: sandbox)\n"; std::cout << " -m, --mode <mode> Modo inicial: sandbox, demo, demo-lite, logo (default: sandbox)\n";
std::cout << " --help Mostrar esta ayuda\n\n"; std::cout << " --help Mostrar esta ayuda\n\n";
std::cout << "Ejemplos:\n"; std::cout << "Ejemplos:\n";
@@ -24,6 +25,7 @@ void printHelp() {
std::cout << " vibe3_physics -w 640 -h 480 -z 2 # 640x480 zoom 2 (ventana 1280x960)\n"; std::cout << " vibe3_physics -w 640 -h 480 -z 2 # 640x480 zoom 2 (ventana 1280x960)\n";
std::cout << " vibe3_physics -f # Fullscreen letterbox (F3)\n"; std::cout << " vibe3_physics -f # Fullscreen letterbox (F3)\n";
std::cout << " vibe3_physics -F # Fullscreen real (F4 - resolución nativa)\n"; std::cout << " vibe3_physics -F # Fullscreen real (F4 - resolución nativa)\n";
std::cout << " vibe3_physics -k # Modo kiosko (pantalla completa real, bloqueado)\n";
std::cout << " vibe3_physics --mode demo # Arrancar en modo DEMO (auto-play)\n"; std::cout << " vibe3_physics --mode demo # Arrancar en modo DEMO (auto-play)\n";
std::cout << " vibe3_physics -m demo-lite # Arrancar en modo DEMO_LITE (solo física)\n"; std::cout << " vibe3_physics -m demo-lite # Arrancar en modo DEMO_LITE (solo física)\n";
std::cout << " vibe3_physics -F --mode logo # Fullscreen + modo LOGO (easter egg)\n\n"; std::cout << " vibe3_physics -F --mode logo # Fullscreen + modo LOGO (easter egg)\n\n";
@@ -36,6 +38,7 @@ int main(int argc, char* argv[]) {
int zoom = 0; int zoom = 0;
bool fullscreen = false; bool fullscreen = false;
bool real_fullscreen = false; bool real_fullscreen = false;
bool kiosk_mode = false;
AppMode initial_mode = AppMode::SANDBOX; // Modo inicial (default: SANDBOX) AppMode initial_mode = AppMode::SANDBOX; // Modo inicial (default: SANDBOX)
// Parsear argumentos // Parsear argumentos
@@ -80,6 +83,8 @@ int main(int argc, char* argv[]) {
fullscreen = true; fullscreen = true;
} else if (strcmp(argv[i], "-F") == 0 || strcmp(argv[i], "--real-fullscreen") == 0) { } else if (strcmp(argv[i], "-F") == 0 || strcmp(argv[i], "--real-fullscreen") == 0) {
real_fullscreen = true; real_fullscreen = true;
} else if (strcmp(argv[i], "-k") == 0 || strcmp(argv[i], "--kiosk") == 0) {
kiosk_mode = true;
} else if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--mode") == 0) { } else if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--mode") == 0) {
if (i + 1 < argc) { if (i + 1 < argc) {
std::string mode_str = argv[++i]; std::string mode_str = argv[++i];
@@ -118,10 +123,13 @@ int main(int argc, char* argv[]) {
return -1; return -1;
} }
// Si se especificó real fullscreen (F4), activar después de inicializar // Si se especificó real fullscreen (F4) o modo kiosko, activar después de inicializar
if (real_fullscreen) { if (real_fullscreen || kiosk_mode) {
engine.toggleRealFullscreen(); engine.toggleRealFullscreen();
} }
if (kiosk_mode) {
engine.setKioskMode(true);
}
engine.run(); engine.run();
engine.shutdown(); engine.shutdown();

View File

@@ -3,9 +3,11 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <cstring>
// Inicializar el puntero estático // Inicializar estáticos
ResourcePack* ResourceManager::resourcePack_ = nullptr; ResourcePack* ResourceManager::resourcePack_ = nullptr;
std::map<std::string, std::vector<unsigned char>> ResourceManager::cache_;
bool ResourceManager::init(const std::string& packFilePath) { bool ResourceManager::init(const std::string& packFilePath) {
// Si ya estaba inicializado, liberar primero // Si ya estaba inicializado, liberar primero
@@ -29,6 +31,7 @@ bool ResourceManager::init(const std::string& packFilePath) {
} }
void ResourceManager::shutdown() { void ResourceManager::shutdown() {
cache_.clear();
if (resourcePack_ != nullptr) { if (resourcePack_ != nullptr) {
delete resourcePack_; delete resourcePack_;
resourcePack_ = nullptr; resourcePack_ = nullptr;
@@ -39,36 +42,41 @@ bool ResourceManager::loadResource(const std::string& resourcePath, unsigned cha
data = nullptr; data = nullptr;
size = 0; size = 0;
// 1. Intentar cargar desde pack (si está disponible) // 1. Consultar caché en RAM (sin I/O)
auto it = cache_.find(resourcePath);
if (it != cache_.end()) {
size = it->second.size();
data = new unsigned char[size];
std::memcpy(data, it->second.data(), size);
return true;
}
// 2. Intentar cargar desde pack (si está disponible)
if (resourcePack_ != nullptr) { if (resourcePack_ != nullptr) {
ResourcePack::ResourceData packData = resourcePack_->loadResource(resourcePath); ResourcePack::ResourceData packData = resourcePack_->loadResource(resourcePath);
if (packData.data != nullptr) { if (packData.data != nullptr) {
cache_[resourcePath] = std::vector<unsigned char>(packData.data, packData.data + packData.size);
data = packData.data; data = packData.data;
size = packData.size; size = packData.size;
return true; return true;
} }
} }
// 2. Fallback: cargar desde disco // 3. Fallback: cargar desde disco
std::ifstream file(resourcePath, std::ios::binary | std::ios::ate); std::ifstream file(resourcePath, std::ios::binary | std::ios::ate);
if (!file) { if (!file) {
// Intentar con "data/" como prefijo si no se encontró
std::string dataPath = "data/" + resourcePath; std::string dataPath = "data/" + resourcePath;
file.open(dataPath, std::ios::binary | std::ios::ate); file.open(dataPath, std::ios::binary | std::ios::ate);
if (!file) { if (!file) { return false; }
return false;
}
} }
// Obtener tamaño del archivo
size = static_cast<size_t>(file.tellg()); size = static_cast<size_t>(file.tellg());
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
// Alocar buffer y leer
data = new unsigned char[size]; data = new unsigned char[size];
file.read(reinterpret_cast<char*>(data), size); file.read(reinterpret_cast<char*>(data), size);
file.close(); file.close();
// Guardar en caché
cache_[resourcePath] = std::vector<unsigned char>(data, data + size);
return true; return true;
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -79,4 +80,7 @@ private:
// Instancia del pack (nullptr si no está cargado) // Instancia del pack (nullptr si no está cargado)
static ResourcePack* resourcePack_; static ResourcePack* resourcePack_;
// Caché en RAM para evitar I/O repetido en el bucle principal
static std::map<std::string, std::vector<unsigned char>> cache_;
}; };