Files
vibe3_physics/source/main.cpp
Sergio c9bcce6f9b style: aplicar fixes de clang-tidy (todo excepto uppercase-literal-suffix)
Corregidos ~2570 issues automáticamente con clang-tidy --fix-errors
más ajustes manuales posteriores:

- modernize: designated-initializers, trailing-return-type, use-auto,
  avoid-c-arrays (→ std::array<>), use-ranges, use-emplace,
  deprecated-headers, use-equals-default, pass-by-value,
  return-braced-init-list, use-default-member-init
- readability: math-missing-parentheses, implicit-bool-conversion,
  braces-around-statements, isolate-declaration, use-std-min-max,
  identifier-naming, else-after-return, redundant-casting,
  convert-member-functions-to-static, make-member-function-const,
  static-accessed-through-instance
- performance: avoid-endl, unnecessary-value-param, type-promotion,
  inefficient-vector-operation
- dead code: XOR_KEY (orphan tras eliminar encryptData/decryptData),
  dead stores en engine.cpp y png_shape.cpp
- NOLINT justificado en 10 funciones con alta complejidad cognitiva
  (initialize, render, main, processEvents, update×3, performDemoAction,
  randomizeOnDemoStart, renderDebugHUD, AppLogo::update)

Compilación: gcc -Wall sin warnings. clang-tidy: 0 issues.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 10:52:07 +01:00

232 lines
9.8 KiB
C++

#include <cstring>
#include <iostream>
#include <string>
#include "defines.hpp"
#include "engine.hpp"
#include "resource_manager.hpp"
// getExecutableDirectory() ya está definido en defines.h como inline
void printHelp() {
std::cout << "ViBe3 Physics - Simulador de físicas avanzadas\n";
std::cout << "\nUso: vibe3_physics [opciones]\n\n";
std::cout << "Opciones:\n";
std::cout << " -w, --width <px> Ancho de resolución (default: " << DEFAULT_SCREEN_WIDTH << ")\n";
std::cout << " -h, --height <px> Alto de resolución (default: " << DEFAULT_SCREEN_HEIGHT << ")\n";
std::cout << " -z, --zoom <n> Zoom de ventana (default: " << DEFAULT_WINDOW_ZOOM << ")\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 << " -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 << " --custom-balls <n> Activa escenario custom (tecla 9) con N pelotas\n";
std::cout << " --skip-benchmark Salta el benchmark y usa el máximo de bolas (50000)\n";
std::cout << " --max-balls <n> Limita el máximo de bolas en modos DEMO/DEMO_LITE\n";
std::cout << " --postfx [efecto] Arrancar con PostFX activo (default: complet): vinyeta, scanlines, cromatica, complet\n";
std::cout << " --vignette <float> Sobreescribir vignette_strength (activa PostFX si no hay --postfx)\n";
std::cout << " --chroma <float> Sobreescribir chroma_strength (activa PostFX si no hay --postfx)\n";
std::cout << " --help Mostrar esta ayuda\n\n";
std::cout << "Ejemplos:\n";
std::cout << " vibe3_physics # " << DEFAULT_SCREEN_WIDTH << "x" << DEFAULT_SCREEN_HEIGHT << " zoom " << DEFAULT_WINDOW_ZOOM << " (default)\n";
std::cout << " vibe3_physics -w 1920 -h 1080 # 1920x1080 zoom 1 (auto)\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 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 -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 << "Nota: Si resolución > pantalla, se usa default. Zoom se ajusta automáticamente.\n";
}
auto main(int argc, char* argv[]) -> int { // NOLINT(readability-function-cognitive-complexity)
int width = 0;
int height = 0;
int zoom = 0;
int custom_balls = 0;
bool fullscreen = false;
bool real_fullscreen = false;
bool kiosk_mode = false;
bool skip_benchmark = false;
int max_balls_override = 0;
int initial_postfx = -1;
float override_vignette = -1.f;
float override_chroma = -1.f;
AppMode initial_mode = AppMode::SANDBOX; // Modo inicial (default: SANDBOX)
// Parsear argumentos
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--help") == 0) {
printHelp();
return 0;
}
if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--width") == 0) {
if (i + 1 < argc) {
width = atoi(argv[++i]);
if (width < 320) {
std::cerr << "Error: Ancho mínimo es 320\n";
return -1;
}
} else {
std::cerr << "Error: -w/--width requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--height") == 0) {
if (i + 1 < argc) {
height = atoi(argv[++i]);
if (height < 240) {
std::cerr << "Error: Alto mínimo es 240\n";
return -1;
}
} else {
std::cerr << "Error: -h/--height requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "-z") == 0 || strcmp(argv[i], "--zoom") == 0) {
if (i + 1 < argc) {
zoom = atoi(argv[++i]);
if (zoom < 1) {
std::cerr << "Error: Zoom mínimo es 1\n";
return -1;
}
} else {
std::cerr << "Error: -z/--zoom requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--fullscreen") == 0) {
fullscreen = true;
} else if (strcmp(argv[i], "-F") == 0 || strcmp(argv[i], "--real-fullscreen") == 0) {
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) {
if (i + 1 < argc) {
std::string mode_str = argv[++i];
if (mode_str == "sandbox") {
initial_mode = AppMode::SANDBOX;
} else if (mode_str == "demo") {
initial_mode = AppMode::DEMO;
} else if (mode_str == "demo-lite") {
initial_mode = AppMode::DEMO_LITE;
} else if (mode_str == "logo") {
initial_mode = AppMode::LOGO;
} else {
std::cerr << "Error: Modo '" << mode_str << "' no válido. Usa: sandbox, demo, demo-lite, logo\n";
return -1;
}
} else {
std::cerr << "Error: -m/--mode requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "--custom-balls") == 0) {
if (i + 1 < argc) {
int n = atoi(argv[++i]);
if (n < 1) {
std::cerr << "Error: --custom-balls requiere un valor >= 1\n";
return -1;
}
custom_balls = n;
} else {
std::cerr << "Error: --custom-balls requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "--skip-benchmark") == 0) {
skip_benchmark = true;
} else if (strcmp(argv[i], "--postfx") == 0) {
// Si no hay valor o el siguiente arg es otra opción, defaultear a complet
if (i + 1 < argc && argv[i + 1][0] != '-') {
std::string fx = argv[++i];
if (fx == "vinyeta") {
initial_postfx = 0;
} else if (fx == "scanlines") {
initial_postfx = 1;
} else if (fx == "cromatica") {
initial_postfx = 2;
} else if (fx == "complet") {
initial_postfx = 3;
} else {
std::cerr << "Error: --postfx '" << fx << "' no válido. Usa: vinyeta, scanlines, cromatica, complet\n";
return -1;
}
} else {
initial_postfx = 3; // default: complet
}
} else if (strcmp(argv[i], "--vignette") == 0) {
if (i + 1 < argc) {
override_vignette = (float)atof(argv[++i]);
} else {
std::cerr << "Error: --vignette requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "--chroma") == 0) {
if (i + 1 < argc) {
override_chroma = (float)atof(argv[++i]);
} else {
std::cerr << "Error: --chroma requiere un valor\n";
return -1;
}
} else if (strcmp(argv[i], "--max-balls") == 0) {
if (i + 1 < argc) {
int n = atoi(argv[++i]);
if (n < 1) {
std::cerr << "Error: --max-balls requiere un valor >= 1\n";
return -1;
}
max_balls_override = n;
} else {
std::cerr << "Error: --max-balls requiere un valor\n";
return -1;
}
} else {
std::cerr << "Error: Opción desconocida '" << argv[i] << "'\n";
printHelp();
return -1;
}
}
// Inicializar sistema de recursos empaquetados (intentar cargar resources.pack)
std::string resources_dir = getResourcesDirectory();
std::string pack_path = resources_dir + "/resources.pack";
ResourceManager::init(pack_path);
Engine engine;
if (custom_balls > 0) {
engine.setCustomScenario(custom_balls); // pre-init: asigna campos antes del benchmark
}
if (max_balls_override > 0) {
engine.setMaxBallsOverride(max_balls_override);
} else if (skip_benchmark) {
engine.setSkipBenchmark();
}
if (initial_postfx >= 0) {
engine.setInitialPostFX(initial_postfx);
}
if (override_vignette >= 0.f || override_chroma >= 0.f) {
if (initial_postfx < 0) {
engine.setInitialPostFX(0);
}
engine.setPostFXParamOverrides(override_vignette, override_chroma);
}
if (!engine.initialize(width, height, zoom, fullscreen, initial_mode)) {
std::cout << "¡Error al inicializar el engine!" << '\n';
return -1;
}
// Si se especificó real fullscreen (F4) o modo kiosko, activar después de inicializar
if (real_fullscreen || kiosk_mode) {
engine.toggleRealFullscreen();
}
if (kiosk_mode) {
engine.setKioskMode(true);
}
engine.run();
engine.shutdown();
return 0;
}