Compare commits
100 Commits
f1bafc8a4f
...
2026-03-18
| Author | SHA1 | Date | |
|---|---|---|---|
| 6aa4a1227e | |||
| 02fdcd4113 | |||
| 7db9e46f95 | |||
| ff6aaef7c6 | |||
| 8e2e681b2c | |||
| f06123feff | |||
| cbe6dc9744 | |||
| dfbd8a430b | |||
| ea27a771ab | |||
| 09303537a4 | |||
| df17e85a8a | |||
| ce5c4681b8 | |||
| b79f1c3424 | |||
| a65544e8b3 | |||
| b9264c96a1 | |||
| fa285519b2 | |||
| 8285a8fafe | |||
| 1a555e03f7 | |||
| af3ed6c2b3 | |||
| a9d7b66e83 | |||
| a929df6b73 | |||
| 3f027d953c | |||
| 1354ed82d2 | |||
| 2fd6d99a61 | |||
| 2fa1684f01 | |||
| 41c76316ef | |||
| ce50a29019 | |||
| f25cb96a91 | |||
| d73781be9f | |||
| 288e4813e8 | |||
| 4d3ddec14e | |||
| ec1700b439 | |||
| 8aa2a112b4 | |||
| dfebd8ece4 | |||
| 827d9f0e76 | |||
| df93d5080d | |||
| 0da4b45fef | |||
| db8acf0331 | |||
| 5a35cc1abf | |||
| d30a4fd440 | |||
| 97c0683f6e | |||
| c3d24cc07d | |||
| 7609b9ef5c | |||
| ad3f5a00e4 | |||
| c91cb1ca56 | |||
| 8d608357b4 | |||
| f73a133756 | |||
| de23327861 | |||
| f6402084eb | |||
| 9909d4c12d | |||
| a929346463 | |||
| c4075f68db | |||
| 399650f8da | |||
| 9b8afa1219 | |||
| 5b674c8ea6 | |||
| 7fac103c51 | |||
| bcceb94c9e | |||
| 1b3d32ba84 | |||
| 7c0a60f140 | |||
| 250b1a640d | |||
| 795fa33e50 | |||
| e7dc8f6d13 | |||
| 9cabbd867f | |||
| 8c2a8857fc | |||
| 3d26bfc6fa | |||
| adfa315a43 | |||
| 18a8812ad7 | |||
| 35f29340db | |||
| abbda0f30b | |||
| 6aacb86d6a | |||
| 0873d80765 | |||
| b73e77e9bc | |||
| 1bb8807060 | |||
| 39c0a24a45 | |||
| 01d1ebd2a3 | |||
| 83ea03fda3 | |||
| d62b8e5f52 | |||
| 0fe2efc051 | |||
| 1c38ab2009 | |||
| 8be4c5586d | |||
| e4636c8e82 | |||
| e2a60e4f87 | |||
| e655c643a5 | |||
| f93879b803 | |||
| b8d3c60e58 | |||
| 5f89299444 | |||
| 33728857ac | |||
| d2f170d313 | |||
| aa57ac7012 | |||
| 0d069da29d | |||
| eb3dd03579 | |||
| a1e2c03efd | |||
| 684ac9823b | |||
| 82e5b6798c | |||
| d93ac04ee3 | |||
| 10a4234d49 | |||
| 0d1608712b | |||
| 68381dc92d | |||
| f00b08b6be | |||
| c50ecbc02a |
22
.gitignore
vendored
22
.gitignore
vendored
@@ -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/
|
||||||
@@ -57,7 +57,6 @@ Makefile
|
|||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
moc_*.h
|
moc_*.h
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
ui_*.h
|
|
||||||
*.qm
|
*.qm
|
||||||
.qmake.stash
|
.qmake.stash
|
||||||
|
|
||||||
@@ -94,4 +93,21 @@ Thumbs.db
|
|||||||
*.temp
|
*.temp
|
||||||
|
|
||||||
# Claude Code
|
# Claude Code
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
|
# Archivos de recursos empaquetados
|
||||||
|
resources.pack
|
||||||
|
|
||||||
|
# Archivos de distribución (resultados de release)
|
||||||
|
*.zip
|
||||||
|
*.dmg
|
||||||
|
*.tar.gz
|
||||||
|
*.AppImage
|
||||||
|
|
||||||
|
# Carpetas temporales de empaquetado
|
||||||
|
vibe3_release/
|
||||||
|
Frameworks/
|
||||||
|
|
||||||
|
# Binarios de herramientas
|
||||||
|
tools/pack_resources
|
||||||
|
tools/*.exe
|
||||||
547
CLAUDE.md
547
CLAUDE.md
@@ -1,547 +0,0 @@
|
|||||||
# Claude Code Session - ViBe3 Physics
|
|
||||||
|
|
||||||
## Estado del Proyecto
|
|
||||||
|
|
||||||
**Proyecto:** ViBe3 Physics - Simulador de sprites con físicas avanzadas
|
|
||||||
**Objetivo:** Implementar nuevas físicas experimentales expandiendo sobre el sistema de delta time
|
|
||||||
**Base:** Migrado desde vibe1_delta con sistema delta time ya implementado
|
|
||||||
|
|
||||||
## Progreso Actual
|
|
||||||
|
|
||||||
### ✅ Completado
|
|
||||||
|
|
||||||
#### 1. **Migración y Setup Inicial**
|
|
||||||
- ✅ Renombrado vibe1_delta → vibe3_physics en todos los archivos
|
|
||||||
- ✅ Carpeta resources → data
|
|
||||||
- ✅ Actualizado CMakeLists.txt, .gitignore, defines.h, README.md
|
|
||||||
- ✅ Añadido .claude/ al .gitignore
|
|
||||||
- ✅ Sistema de compilación CMake funcionando
|
|
||||||
|
|
||||||
#### 2. **Sistema de Físicas Base (Heredado)**
|
|
||||||
- ✅ **Delta time implementado** - Física independiente del framerate
|
|
||||||
- ✅ Contador FPS en tiempo real (esquina superior derecha, amarillo)
|
|
||||||
- ✅ Control V-Sync dinámico con tecla "V" (ON/OFF)
|
|
||||||
- ✅ Display V-Sync (esquina superior izquierda, cian)
|
|
||||||
- ✅ **Sistema de temas visuales** - 4 temas (SUNSET/OCEAN/NEON/FOREST)
|
|
||||||
- ✅ **Batch rendering optimizado** - Maneja hasta 100,000 sprites
|
|
||||||
|
|
||||||
#### 3. **NUEVA CARACTERÍSTICA: Gravedad Direccional** 🎯
|
|
||||||
- ✅ **Enum GravityDirection** (UP/DOWN/LEFT/RIGHT) en defines.h
|
|
||||||
- ✅ **Ball class actualizada** para física multi-direccional
|
|
||||||
- ✅ **Detección de superficie inteligente** - Adaptada a cada dirección
|
|
||||||
- ✅ **Fricción direccional** - Se aplica en la superficie correcta
|
|
||||||
- ✅ **Controles de cursor** - Cambio dinámico de gravedad
|
|
||||||
- ✅ **Debug display actualizado** - Muestra dirección actual
|
|
||||||
|
|
||||||
#### 4. **NUEVA CARACTERÍSTICA: Coeficientes de Rebote Variables** ⚡
|
|
||||||
- ✅ **Rango ampliado** - De 0.60-0.89 a 0.30-0.95 (+120% variabilidad)
|
|
||||||
- ✅ **Comportamientos diversos** - Desde pelotas super rebotonas a muy amortiguadas
|
|
||||||
- ✅ **Debug display** - Muestra coeficiente LOSS de primera pelota
|
|
||||||
- ✅ **Física realista** - Elimina sincronización entre pelotas
|
|
||||||
|
|
||||||
#### 5. **🎯 NUEVA CARACTERÍSTICA: Modo RotoBall (Esfera 3D Rotante)** 🌐
|
|
||||||
- ✅ **Fibonacci Sphere Algorithm** - Distribución uniforme de puntos en esfera 3D
|
|
||||||
- ✅ **Rotación dual (X/Y)** - Efecto visual dinámico estilo demoscene
|
|
||||||
- ✅ **Profundidad Z simulada** - Color mod según distancia (oscuro=lejos, brillante=cerca)
|
|
||||||
- ✅ **Física de atracción con resorte** - Sistema de fuerzas con conservación de momento
|
|
||||||
- ✅ **Transición física realista** - Pelotas atraídas a esfera rotante con aceleración
|
|
||||||
- ✅ **Amortiguación variable** - Mayor damping cerca del punto (estabilización)
|
|
||||||
- ✅ **Sin sprites adicionales** - Usa SDL_SetTextureColorMod para profundidad
|
|
||||||
- ✅ **Proyección ortográfica** - Coordenadas 3D → 2D en tiempo real
|
|
||||||
- ✅ **Conservación de inercia** - Al salir mantienen velocidad tangencial
|
|
||||||
- ✅ **Compatible con temas** - Mantiene paleta de colores activa
|
|
||||||
- ✅ **Performance optimizado** - Funciona con 1-100,000 pelotas
|
|
||||||
|
|
||||||
### 📋 Controles Actuales
|
|
||||||
|
|
||||||
| Tecla | Acción |
|
|
||||||
|-------|--------|
|
|
||||||
| **↑** | **Gravedad hacia ARRIBA** |
|
|
||||||
| **↓** | **Gravedad hacia ABAJO** |
|
|
||||||
| **←** | **Gravedad hacia IZQUIERDA** |
|
|
||||||
| **→** | **Gravedad hacia DERECHA** |
|
|
||||||
| **C** | **🌐 MODO ROTOBALL - Toggle esfera 3D rotante** |
|
|
||||||
| V | Alternar V-Sync ON/OFF |
|
|
||||||
| H | **Toggle debug display (FPS, V-Sync, física, gravedad, modo)** |
|
|
||||||
| Num 1-5 | Selección directa de tema (1-Atardecer/2-Océano/3-Neón/4-Bosque/5-RGB) |
|
|
||||||
| T | Ciclar entre temas de colores |
|
|
||||||
| 1-8 | Cambiar número de pelotas (1 a 100,000) |
|
|
||||||
| ESPACIO | Impulsar pelotas hacia arriba |
|
|
||||||
| G | Alternar gravedad ON/OFF (mantiene dirección) |
|
|
||||||
| ESC | Salir |
|
|
||||||
|
|
||||||
### 🎯 Debug Display (Tecla H)
|
|
||||||
|
|
||||||
Cuando está activado muestra:
|
|
||||||
```
|
|
||||||
FPS: 75 # Esquina superior derecha (amarillo)
|
|
||||||
VSYNC ON # Esquina superior izquierda (cian)
|
|
||||||
GRAV 720 # Magnitud gravedad (magenta)
|
|
||||||
VY -145 # Velocidad Y primera pelota (magenta)
|
|
||||||
SURFACE YES # En superficie (magenta)
|
|
||||||
LOSS 0.73 # Coeficiente rebote primera pelota (magenta)
|
|
||||||
GRAVITY DOWN # Dirección actual (amarillo)
|
|
||||||
THEME SUNSET # Tema activo (amarillo claro)
|
|
||||||
MODE PHYSICS # Modo simulación actual (verde claro) - PHYSICS/ROTOBALL
|
|
||||||
```
|
|
||||||
|
|
||||||
## Arquitectura Actual
|
|
||||||
|
|
||||||
```
|
|
||||||
vibe3_physics/
|
|
||||||
├── source/
|
|
||||||
│ ├── main.cpp # Bucle principal + controles + debug
|
|
||||||
│ ├── ball.h/.cpp # Clase Ball con física direccional
|
|
||||||
│ ├── defines.h # Constantes + enum GravityDirection
|
|
||||||
│ └── external/ # Utilidades externas
|
|
||||||
│ ├── texture.h/.cpp # Gestión texturas + nearest filter
|
|
||||||
│ ├── sprite.h/.cpp # Sistema sprites
|
|
||||||
│ ├── dbgtxt.h # Debug text + nearest filter
|
|
||||||
│ └── stb_image.h # Carga imágenes
|
|
||||||
├── data/ # Recursos (antes resources/)
|
|
||||||
│ └── ball.png # Textura pelota 10x10px
|
|
||||||
├── CMakeLists.txt # Build system
|
|
||||||
└── CLAUDE.md # Este archivo de seguimiento
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sistema de Gravedad Direccional
|
|
||||||
|
|
||||||
### 🔧 Implementación Técnica
|
|
||||||
|
|
||||||
#### Enum y Estados
|
|
||||||
```cpp
|
|
||||||
enum class GravityDirection {
|
|
||||||
DOWN, // ↓ Gravedad hacia abajo (por defecto)
|
|
||||||
UP, // ↑ Gravedad hacia arriba
|
|
||||||
LEFT, // ← Gravedad hacia la izquierda
|
|
||||||
RIGHT // → Gravedad hacia la derecha
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Lógica de Física por Dirección
|
|
||||||
- **DOWN**: Pelotas caen hacia abajo, fricción en suelo inferior
|
|
||||||
- **UP**: Pelotas "caen" hacia arriba, fricción en techo
|
|
||||||
- **LEFT**: Pelotas "caen" hacia izquierda, fricción en pared izquierda
|
|
||||||
- **RIGHT**: Pelotas "caen" hacia derecha, fricción en pared derecha
|
|
||||||
|
|
||||||
#### Cambios en Ball Class
|
|
||||||
- `on_floor_` → `on_surface_` (más genérico)
|
|
||||||
- `gravity_direction_` (nuevo miembro)
|
|
||||||
- `setGravityDirection()` (nueva función)
|
|
||||||
- `update()` completamente reescrito para lógica direccional
|
|
||||||
|
|
||||||
## Lecciones Aprendidas de ViBe2 Modules
|
|
||||||
|
|
||||||
### ✅ Éxitos de Modularización
|
|
||||||
- **C++20 modules** son viables para código propio
|
|
||||||
- **CMake + Ninja** funciona bien para modules
|
|
||||||
- **Separación clara** de responsabilidades mejora arquitectura
|
|
||||||
|
|
||||||
### ❌ Limitaciones Encontradas
|
|
||||||
- **SDL3 + modules** generan conflictos irresolubles
|
|
||||||
- **Bibliotecas externas** requieren includes tradicionales
|
|
||||||
- **Enfoque híbrido** (modules propios + includes externos) es más práctico
|
|
||||||
|
|
||||||
### 🎯 Decisión para ViBe3 Physics
|
|
||||||
- **Headers tradicionales** (.h/.cpp) por compatibilidad
|
|
||||||
- **Enfoque en características** antes que arquitectura
|
|
||||||
- **Organización por clases** en lugar de modules inicialmente
|
|
||||||
|
|
||||||
## Sistema de Coeficientes de Rebote Variables
|
|
||||||
|
|
||||||
### 🔧 Implementación Técnica
|
|
||||||
|
|
||||||
#### Problema Anterior
|
|
||||||
```cpp
|
|
||||||
// Sistema ANTIGUO - Poca variabilidad
|
|
||||||
loss_ = ((rand() % 30) * 0.01f) + 0.6f; // 0.60 - 0.89 (diferencia: 0.29)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Resultado**: Pelotas con comportamientos muy similares → Sincronización visible
|
|
||||||
|
|
||||||
#### Solución Implementada
|
|
||||||
```cpp
|
|
||||||
// Sistema NUEVO - Alta variabilidad
|
|
||||||
loss_ = ((rand() % 66) * 0.01f) + 0.30f; // 0.30 - 0.95 (diferencia: 0.65)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 🎯 Tipos de Comportamiento
|
|
||||||
|
|
||||||
#### Categorías de Materiales
|
|
||||||
- **🏀 Super Rebotona** (0.85-0.95): Casi no pierde energía, rebota muchas veces
|
|
||||||
- **⚽ Normal** (0.65-0.85): Comportamiento estándar equilibrado
|
|
||||||
- **🎾 Amortiguada** (0.45-0.65): Pierde energía moderada, se estabiliza
|
|
||||||
- **🏐 Muy Amortiguada** (0.30-0.45): Se para rápidamente, pocas rebotes
|
|
||||||
|
|
||||||
### ✅ Beneficios Conseguidos
|
|
||||||
- **+120% variabilidad** en coeficientes de rebote
|
|
||||||
- **Eliminación de sincronización** entre pelotas
|
|
||||||
- **Comportamientos diversos** visibles inmediatamente
|
|
||||||
- **Física más realista** con materiales diferentes
|
|
||||||
- **Debug display** para monitoreo en tiempo real
|
|
||||||
|
|
||||||
## 🚀 Próximos Pasos - Físicas Avanzadas
|
|
||||||
|
|
||||||
### Ideas Pendientes de Implementación
|
|
||||||
|
|
||||||
#### 1. **Colisiones Entre Partículas**
|
|
||||||
- Detección de colisión ball-to-ball
|
|
||||||
- Física de rebotes entre pelotas
|
|
||||||
- Conservación de momentum
|
|
||||||
|
|
||||||
#### 2. **Materiales y Propiedades**
|
|
||||||
- Diferentes coeficientes de rebote por pelota
|
|
||||||
- Fricción variable por material
|
|
||||||
- Densidad y masa como propiedades
|
|
||||||
|
|
||||||
#### 3. **Fuerzas Externas**
|
|
||||||
- **Viento** - Fuerza horizontal constante
|
|
||||||
- **Campos magnéticos** - Atracción/repulsión a puntos
|
|
||||||
- **Turbulencia** - Fuerzas aleatorias localizadas
|
|
||||||
|
|
||||||
#### 4. **Interactividad Avanzada**
|
|
||||||
- Click para aplicar fuerzas puntuales
|
|
||||||
- Arrastrar para crear campos de fuerza
|
|
||||||
- Herramientas de "pincel" de física
|
|
||||||
|
|
||||||
#### 5. **Visualización Avanzada**
|
|
||||||
- **Trails** - Estelas de movimiento
|
|
||||||
- **Heatmaps** - Visualización de velocidad/energía
|
|
||||||
- **Vectores de fuerza** - Visualizar gravedad y fuerzas
|
|
||||||
|
|
||||||
#### 6. **Optimizaciones**
|
|
||||||
- Spatial partitioning para colisiones
|
|
||||||
- Level-of-detail para muchas partículas
|
|
||||||
- GPU compute shaders para física masiva
|
|
||||||
|
|
||||||
### 🎮 Controles Futuros Sugeridos
|
|
||||||
```
|
|
||||||
Mouse Click: Aplicar fuerza puntual
|
|
||||||
Mouse Drag: Crear campo de fuerza
|
|
||||||
Mouse Wheel: Ajustar intensidad
|
|
||||||
R: Reset todas las pelotas
|
|
||||||
P: Pausa/Resume física
|
|
||||||
M: Modo materiales
|
|
||||||
W: Toggle viento
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🌐 Implementación Técnica: Modo RotoBall
|
|
||||||
|
|
||||||
### Algoritmo Fibonacci Sphere
|
|
||||||
|
|
||||||
Distribución uniforme de puntos en una esfera usando la secuencia de Fibonacci:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
const float golden_ratio = (1.0f + sqrtf(5.0f)) / 2.0f;
|
|
||||||
const float angle_increment = PI * 2.0f * golden_ratio;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_points; i++) {
|
|
||||||
float t = static_cast<float>(i) / static_cast<float>(num_points);
|
|
||||||
float phi = acosf(1.0f - 2.0f * t); // Latitud: 0 a π
|
|
||||||
float theta = angle_increment * i; // Longitud: 0 a 2π * golden_ratio
|
|
||||||
|
|
||||||
// Coordenadas esféricas → cartesianas
|
|
||||||
float x = cosf(theta) * sinf(phi) * radius;
|
|
||||||
float y = sinf(theta) * sinf(phi) * radius;
|
|
||||||
float z = cosf(phi) * radius;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ventajas:**
|
|
||||||
- Distribución uniforme sin clustering en polos
|
|
||||||
- O(1) cálculo por punto (no requiere iteraciones)
|
|
||||||
- Visualmente perfecto para demoscene effects
|
|
||||||
|
|
||||||
### Rotación 3D (Matrices de Rotación)
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Rotación en eje Y (horizontal)
|
|
||||||
float cos_y = cosf(angle_y);
|
|
||||||
float sin_y = sinf(angle_y);
|
|
||||||
float x_rot = x * cos_y - z * sin_y;
|
|
||||||
float z_rot = x * sin_y + z * cos_y;
|
|
||||||
|
|
||||||
// Rotación en eje X (vertical)
|
|
||||||
float cos_x = cosf(angle_x);
|
|
||||||
float sin_x = sinf(angle_x);
|
|
||||||
float y_rot = y * cos_x - z_rot * sin_x;
|
|
||||||
float z_final = y * sin_x + z_rot * cos_x;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Velocidades:**
|
|
||||||
- Eje Y: 1.5 rad/s (rotación principal horizontal)
|
|
||||||
- Eje X: 0.8 rad/s (rotación secundaria vertical)
|
|
||||||
- Ratio Y/X ≈ 2:1 para efecto visual dinámico
|
|
||||||
|
|
||||||
### Proyección 3D → 2D
|
|
||||||
|
|
||||||
**Proyección Ortográfica:**
|
|
||||||
```cpp
|
|
||||||
float screen_x = center_x + x_rotated;
|
|
||||||
float screen_y = center_y + y_rotated;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Profundidad Z (Color Modulation):**
|
|
||||||
```cpp
|
|
||||||
// Normalizar Z de [-radius, +radius] a [0, 1]
|
|
||||||
float z_normalized = (z_final + radius) / (2.0f * radius);
|
|
||||||
|
|
||||||
// Mapear a rango de brillo [MIN_BRIGHTNESS, MAX_BRIGHTNESS]
|
|
||||||
float brightness_factor = (MIN + z_normalized * (MAX - MIN)) / 255.0f;
|
|
||||||
|
|
||||||
// Aplicar a color RGB
|
|
||||||
int r_mod = color.r * brightness_factor;
|
|
||||||
int g_mod = color.g * brightness_factor;
|
|
||||||
int b_mod = color.b * brightness_factor;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Efecto visual:**
|
|
||||||
- Z cerca (+radius): Brillo máximo (255) → Color original
|
|
||||||
- Z lejos (-radius): Brillo mínimo (50) → Color oscuro
|
|
||||||
- Simula profundidad sin sprites adicionales
|
|
||||||
|
|
||||||
### Transición Suave (Interpolación)
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Progress de 0.0 a 1.0 en ROTOBALL_TRANSITION_TIME (1.5s)
|
|
||||||
transition_progress += delta_time / ROTOBALL_TRANSITION_TIME;
|
|
||||||
|
|
||||||
// Lerp desde posición actual a posición de esfera
|
|
||||||
float lerp_x = current_x + (target_sphere_x - current_x) * progress;
|
|
||||||
float lerp_y = current_y + (target_sphere_y - current_y) * progress;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Características:**
|
|
||||||
- Independiente del framerate (usa delta_time)
|
|
||||||
- Suave y orgánico
|
|
||||||
- Sin pop visual
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
- **Batch rendering**: Una sola llamada `SDL_RenderGeometry` para todos los puntos
|
|
||||||
- **Recalculación**: Fibonacci sphere recalculada cada frame (O(n) predecible)
|
|
||||||
- **Sin malloc**: Usa datos ya almacenados en Ball objects
|
|
||||||
- **Color mod**: CPU-side, sin overhead GPU adicional
|
|
||||||
|
|
||||||
**Rendimiento medido:**
|
|
||||||
- 100 pelotas: >300 FPS
|
|
||||||
- 1,000 pelotas: >200 FPS
|
|
||||||
- 10,000 pelotas: >100 FPS
|
|
||||||
- 100,000 pelotas: >60 FPS (mismo que modo física)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔬 Sistema de Física con Atracción (Spring Force)
|
|
||||||
|
|
||||||
### Mejora Implementada: Transición Física Realista
|
|
||||||
|
|
||||||
**Problema anterior:** Interpolación lineal artificial (lerp) sin física real
|
|
||||||
**Solución:** Sistema de resorte (Hooke's Law) con conservación de momento
|
|
||||||
|
|
||||||
### Ecuaciones Implementadas
|
|
||||||
|
|
||||||
#### Fuerza de Resorte (Ley de Hooke)
|
|
||||||
```cpp
|
|
||||||
F_spring = k * (target - position)
|
|
||||||
```
|
|
||||||
- `k = 300.0`: Constante de rigidez del resorte (N/m)
|
|
||||||
- Mayor k = atracción más fuerte
|
|
||||||
|
|
||||||
#### Fuerza de Amortiguación (Damping)
|
|
||||||
```cpp
|
|
||||||
F_damping = c * velocity
|
|
||||||
F_total = F_spring - F_damping
|
|
||||||
```
|
|
||||||
- `c_base = 15.0`: Amortiguación lejos del punto
|
|
||||||
- `c_near = 50.0`: Amortiguación cerca (estabilización)
|
|
||||||
- Evita oscilaciones infinitas
|
|
||||||
|
|
||||||
#### Aplicación de Fuerzas
|
|
||||||
```cpp
|
|
||||||
acceleration = F_total / mass // Asumiendo mass = 1
|
|
||||||
velocity += acceleration * deltaTime
|
|
||||||
position += velocity * deltaTime
|
|
||||||
```
|
|
||||||
|
|
||||||
### Comportamiento Físico
|
|
||||||
|
|
||||||
**Al activar RotoBall (tecla C):**
|
|
||||||
1. Esfera comienza a rotar inmediatamente
|
|
||||||
2. Cada pelota mantiene su velocidad actual (`vx`, `vy`)
|
|
||||||
3. Se aplica fuerza de atracción hacia punto móvil en esfera
|
|
||||||
4. Las pelotas se aceleran hacia sus destinos
|
|
||||||
5. Amortiguación las estabiliza al llegar
|
|
||||||
|
|
||||||
**Durante RotoBall:**
|
|
||||||
- Punto destino rota constantemente (actualización cada frame)
|
|
||||||
- Fuerza se recalcula hacia posición rotada
|
|
||||||
- Pelotas "persiguen" su punto mientras este se mueve
|
|
||||||
- Efecto: Convergencia con ligera oscilación orbital
|
|
||||||
|
|
||||||
**Al desactivar RotoBall (tecla C):**
|
|
||||||
1. Atracción se desactiva (`enableRotoBallAttraction(false)`)
|
|
||||||
2. Pelotas conservan velocidad tangencial actual
|
|
||||||
3. Gravedad vuelve a aplicarse
|
|
||||||
4. Transición suave a física normal
|
|
||||||
|
|
||||||
### Constantes Físicas Ajustables
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// En defines.h (VALORES ACTUALES - Amortiguamiento crítico)
|
|
||||||
ROTOBALL_SPRING_K = 300.0f; // Rigidez resorte
|
|
||||||
ROTOBALL_DAMPING_BASE = 35.0f; // Amortiguación lejos (crítico ≈ 2*√k*m)
|
|
||||||
ROTOBALL_DAMPING_NEAR = 80.0f; // Amortiguación cerca (absorción rápida)
|
|
||||||
ROTOBALL_NEAR_THRESHOLD = 5.0f; // Distancia "cerca" (px)
|
|
||||||
ROTOBALL_MAX_FORCE = 1000.0f; // Límite fuerza (seguridad)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Changelog de Ajustes:**
|
|
||||||
- **v1:** `DAMPING_BASE=15.0, NEAR=50.0` → Oscilación visible (subdamped)
|
|
||||||
- **v2:** `DAMPING_BASE=35.0, NEAR=80.0` → **Absorción rápida sin oscilación** ✅
|
|
||||||
|
|
||||||
### Ajustes Recomendados
|
|
||||||
|
|
||||||
**Si siguen oscilando (poco probable):**
|
|
||||||
```cpp
|
|
||||||
ROTOBALL_DAMPING_BASE = 50.0f; // Amortiguamiento super crítico
|
|
||||||
ROTOBALL_DAMPING_NEAR = 100.0f; // Absorción instantánea
|
|
||||||
```
|
|
||||||
|
|
||||||
**Si llegan muy lento:**
|
|
||||||
```cpp
|
|
||||||
ROTOBALL_SPRING_K = 400.0f; // Más fuerza
|
|
||||||
ROTOBALL_DAMPING_BASE = 40.0f; // Compensar con más damping
|
|
||||||
```
|
|
||||||
|
|
||||||
**Si quieres más "rebote" visual:**
|
|
||||||
```cpp
|
|
||||||
ROTOBALL_DAMPING_BASE = 25.0f; // Menos amortiguación
|
|
||||||
ROTOBALL_DAMPING_NEAR = 60.0f; // Ligera oscilación
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ventajas del Sistema
|
|
||||||
|
|
||||||
✅ **Física realista**: Conservación de momento angular
|
|
||||||
✅ **Transición orgánica**: Aceleración natural, no artificial
|
|
||||||
✅ **Inercia preservada**: Al salir conservan velocidad
|
|
||||||
✅ **Estabilización automática**: Damping evita oscilaciones infinitas
|
|
||||||
✅ **Performance**: O(1) por pelota, muy eficiente
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Z-Sorting (Painter's Algorithm)
|
|
||||||
|
|
||||||
### Problema de Renderizado 3D
|
|
||||||
|
|
||||||
**Antes del Z-sorting:**
|
|
||||||
- Pelotas renderizadas en orden fijo del vector: `Ball[0] → Ball[1] → ... → Ball[N]`
|
|
||||||
- Orden aleatorio respecto a profundidad Z
|
|
||||||
- **Problema:** Pelotas oscuras (fondo) pintadas sobre claras (frente)
|
|
||||||
- Resultado: Inversión de profundidad visual incorrecta
|
|
||||||
|
|
||||||
**Después del Z-sorting:**
|
|
||||||
- Pelotas ordenadas por `depth_brightness` antes de renderizar
|
|
||||||
- Painter's Algorithm: **Fondo primero, frente último**
|
|
||||||
- Pelotas oscuras (Z bajo) renderizadas primero
|
|
||||||
- Pelotas claras (Z alto) renderizadas último (encima)
|
|
||||||
- **Resultado:** Oclusión 3D correcta ✅
|
|
||||||
|
|
||||||
### Implementación (engine.cpp::render())
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
if (current_mode_ == SimulationMode::ROTOBALL) {
|
|
||||||
// 1. Crear vector de índices
|
|
||||||
std::vector<size_t> render_order;
|
|
||||||
for (size_t i = 0; i < balls_.size(); i++) {
|
|
||||||
render_order.push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Ordenar por depth_brightness (menor primero = fondo primero)
|
|
||||||
std::sort(render_order.begin(), render_order.end(),
|
|
||||||
[this](size_t a, size_t b) {
|
|
||||||
return balls_[a]->getDepthBrightness() < balls_[b]->getDepthBrightness();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. Renderizar en orden de profundidad
|
|
||||||
for (size_t idx : render_order) {
|
|
||||||
// Renderizar balls_[idx]...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Complejidad y Performance
|
|
||||||
|
|
||||||
| Operación | Complejidad | Tiempo (estimado) |
|
|
||||||
|-----------|-------------|-------------------|
|
|
||||||
| Crear índices | O(n) | ~0.001ms (1K pelotas) |
|
|
||||||
| std::sort | O(n log n) | ~0.01ms (1K pelotas) |
|
|
||||||
| Renderizar | O(n) | ~variable |
|
|
||||||
| **Total** | **O(n log n)** | **~0.15ms (10K pelotas)** |
|
|
||||||
|
|
||||||
**Impacto en FPS:**
|
|
||||||
- 100 pelotas: Imperceptible (<0.001ms)
|
|
||||||
- 1,000 pelotas: Imperceptible (~0.01ms)
|
|
||||||
- 10,000 pelotas: Leve (~0.15ms, ~1-2 FPS)
|
|
||||||
- 100,000 pelotas: Moderado (~2ms, ~10-15 FPS)
|
|
||||||
|
|
||||||
### Optimizaciones Aplicadas
|
|
||||||
|
|
||||||
✅ **Solo en modo RotoBall**: Modo física no tiene overhead
|
|
||||||
✅ **Vector de índices**: `balls_` no se modifica (física estable)
|
|
||||||
✅ **Reserve() usado**: Evita realocaciones
|
|
||||||
✅ **Lambda eficiente**: Acceso directo sin copias
|
|
||||||
|
|
||||||
### Resultado Visual
|
|
||||||
|
|
||||||
✅ **Profundidad correcta**: Fondo detrás, frente delante
|
|
||||||
✅ **Oclusión apropiada**: Pelotas claras cubren oscuras
|
|
||||||
✅ **Efecto 3D realista**: Percepción de profundidad correcta
|
|
||||||
✅ **Sin artefactos visuales**: Ordenamiento estable cada frame
|
|
||||||
|
|
||||||
## Métricas del Proyecto
|
|
||||||
|
|
||||||
### ✅ Logros Actuales
|
|
||||||
- **Compilación exitosa** con CMake
|
|
||||||
- **Commit inicial** creado (dec8d43)
|
|
||||||
- **17 archivos** versionados
|
|
||||||
- **9,767 líneas** de código
|
|
||||||
- **Física direccional** 100% funcional
|
|
||||||
- **Coeficientes variables** implementados
|
|
||||||
|
|
||||||
### 🎯 Objetivos Cumplidos
|
|
||||||
- ✅ Migración limpia desde vibe1_delta
|
|
||||||
- ✅ Sistema de gravedad direccional implementado
|
|
||||||
- ✅ Coeficientes de rebote variables (+120% diversidad)
|
|
||||||
- ✅ **Modo RotoBall (esfera 3D rotante) implementado**
|
|
||||||
- ✅ **Fibonacci sphere algorithm funcionando**
|
|
||||||
- ✅ **Profundidad Z con color modulation**
|
|
||||||
- ✅ Debug display completo y funcional
|
|
||||||
- ✅ Controles intuitivos con teclas de cursor
|
|
||||||
- ✅ Eliminación de sincronización entre pelotas
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Comandos Útiles
|
|
||||||
|
|
||||||
### Compilación
|
|
||||||
```bash
|
|
||||||
mkdir -p build && cd build && cmake .. && cmake --build .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ejecución
|
|
||||||
```bash
|
|
||||||
./vibe3_physics.exe # Windows
|
|
||||||
./vibe3_physics # Linux/macOS
|
|
||||||
```
|
|
||||||
|
|
||||||
### Git
|
|
||||||
```bash
|
|
||||||
git status # Ver cambios
|
|
||||||
git add . # Añadir archivos
|
|
||||||
git commit -m "..." # Crear commit
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Archivo de seguimiento para sesiones Claude Code - ViBe3 Physics*
|
|
||||||
*Actualizado: Implementación de gravedad direccional completada*
|
|
||||||
@@ -16,8 +16,16 @@ if (NOT SDL3_FOUND)
|
|||||||
message(FATAL_ERROR "SDL3 no encontrado. Por favor, verifica su instalación.")
|
message(FATAL_ERROR "SDL3 no encontrado. Por favor, verifica su instalación.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Buscar SDL3_ttf
|
||||||
|
find_package(SDL3_ttf REQUIRED)
|
||||||
|
|
||||||
|
# Si no se encuentra SDL3_ttf, generar un error
|
||||||
|
if (NOT SDL3_ttf_FOUND)
|
||||||
|
message(FATAL_ERROR "SDL3_ttf no encontrado. Por favor, verifica su instalación.")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Archivos fuente (excluir main_old.cpp)
|
# Archivos fuente (excluir main_old.cpp)
|
||||||
file(GLOB SOURCE_FILES source/*.cpp source/external/*.cpp source/shapes/*.cpp source/themes/*.cpp)
|
file(GLOB SOURCE_FILES source/*.cpp source/external/*.cpp source/boids_mgr/*.cpp source/input/*.cpp source/scene/*.cpp source/shapes/*.cpp source/shapes_mgr/*.cpp source/state/*.cpp source/themes/*.cpp source/text/*.cpp source/ui/*.cpp)
|
||||||
list(REMOVE_ITEM SOURCE_FILES "${CMAKE_SOURCE_DIR}/source/main_old.cpp")
|
list(REMOVE_ITEM SOURCE_FILES "${CMAKE_SOURCE_DIR}/source/main_old.cpp")
|
||||||
|
|
||||||
# Comprobar si se encontraron archivos fuente
|
# Comprobar si se encontraron archivos fuente
|
||||||
@@ -28,17 +36,20 @@ endif()
|
|||||||
# Detectar la plataforma y configuraciones específicas
|
# Detectar la plataforma y configuraciones específicas
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(PLATFORM windows)
|
set(PLATFORM windows)
|
||||||
set(LINK_LIBS ${SDL3_LIBRARIES} mingw32 ws2_32)
|
set(LINK_LIBS SDL3::SDL3 SDL3_ttf::SDL3_ttf mingw32 ws2_32)
|
||||||
elseif(UNIX AND NOT APPLE)
|
elseif(UNIX AND NOT APPLE)
|
||||||
set(PLATFORM linux)
|
set(PLATFORM linux)
|
||||||
set(LINK_LIBS ${SDL3_LIBRARIES})
|
set(LINK_LIBS SDL3::SDL3 SDL3_ttf::SDL3_ttf)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
set(PLATFORM macos)
|
set(PLATFORM macos)
|
||||||
set(LINK_LIBS ${SDL3_LIBRARIES})
|
set(LINK_LIBS SDL3::SDL3 SDL3_ttf::SDL3_ttf)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Incluir directorios de SDL3
|
# Incluir directorios de SDL3 y SDL3_ttf
|
||||||
include_directories(${SDL3_INCLUDE_DIRS})
|
include_directories(${SDL3_INCLUDE_DIRS} ${SDL3_ttf_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# Incluir directorio source/ para poder usar includes desde la raíz del proyecto
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/source)
|
||||||
|
|
||||||
# Añadir el ejecutable reutilizando el nombre del proyecto
|
# Añadir el ejecutable reutilizando el nombre del proyecto
|
||||||
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
||||||
@@ -48,3 +59,8 @@ set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAK
|
|||||||
|
|
||||||
# Enlazar las bibliotecas necesarias
|
# Enlazar las bibliotecas necesarias
|
||||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIBS})
|
target_link_libraries(${PROJECT_NAME} ${LINK_LIBS})
|
||||||
|
|
||||||
|
# Tool: pack_resources
|
||||||
|
add_executable(pack_resources tools/pack_resources.cpp source/resource_pack.cpp)
|
||||||
|
target_include_directories(pack_resources PRIVATE ${CMAKE_SOURCE_DIR}/source)
|
||||||
|
set_target_properties(pack_resources PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/tools")
|
||||||
|
|||||||
193
Makefile
193
Makefile
@@ -42,64 +42,69 @@ endif
|
|||||||
|
|
||||||
# Nombres para los ficheros de lanzamiento
|
# Nombres para los ficheros de lanzamiento
|
||||||
WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip
|
WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip
|
||||||
MACOS_INTEL_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-intel.dmg
|
MACOS_INTEL_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-intel.dmg
|
||||||
MACOS_APPLE_SILICON_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-apple-silicon.dmg
|
MACOS_APPLE_SILICON_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-apple-silicon.dmg
|
||||||
LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz
|
LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz
|
||||||
RASPI_RELEASE := $(TARGET_FILE)-$(VERSION)-raspberry.tar.gz
|
RASPI_RELEASE := $(TARGET_FILE)-$(VERSION)-raspberry.tar.gz
|
||||||
|
|
||||||
# Lista completa de archivos fuente (basada en estructura de ViBe3)
|
# Lista completa de archivos fuente (detección automática con wildcards, como CMakeLists.txt)
|
||||||
APP_SOURCES := \
|
APP_SOURCES := $(wildcard source/*.cpp) \
|
||||||
source/ball.cpp \
|
$(wildcard source/external/*.cpp) \
|
||||||
source/engine.cpp \
|
$(wildcard source/shapes/*.cpp) \
|
||||||
source/main.cpp \
|
$(wildcard source/themes/*.cpp) \
|
||||||
source/resource_pack.cpp \
|
$(wildcard source/state/*.cpp) \
|
||||||
source/external/mouse.cpp \
|
$(wildcard source/input/*.cpp) \
|
||||||
source/external/sprite.cpp \
|
$(wildcard source/scene/*.cpp) \
|
||||||
source/external/texture.cpp \
|
$(wildcard source/shapes_mgr/*.cpp) \
|
||||||
source/shapes/atom_shape.cpp \
|
$(wildcard source/boids_mgr/*.cpp) \
|
||||||
source/shapes/cube_shape.cpp \
|
$(wildcard source/text/*.cpp) \
|
||||||
source/shapes/cylinder_shape.cpp \
|
$(wildcard source/ui/*.cpp)
|
||||||
source/shapes/helix_shape.cpp \
|
|
||||||
source/shapes/icosahedron_shape.cpp \
|
# Excluir archivos antiguos si existen
|
||||||
source/shapes/png_shape.cpp \
|
APP_SOURCES := $(filter-out source/main_old.cpp, $(APP_SOURCES))
|
||||||
source/shapes/sphere_shape.cpp \
|
|
||||||
source/shapes/torus_shape.cpp \
|
|
||||||
source/shapes/wave_grid_shape.cpp
|
|
||||||
|
|
||||||
# Includes
|
# Includes
|
||||||
INCLUDES := -Isource -Isource/external
|
INCLUDES := -Isource -Isource/external
|
||||||
|
|
||||||
# Variables según el sistema operativo
|
# Variables según el sistema operativo
|
||||||
|
CXXFLAGS_BASE := -std=c++20 -Wall
|
||||||
|
CXXFLAGS := $(CXXFLAGS_BASE) -Os -ffunction-sections -fdata-sections
|
||||||
|
CXXFLAGS_DEBUG := $(CXXFLAGS_BASE) -g -D_DEBUG
|
||||||
|
LDFLAGS :=
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
FixPath = $(subst /,\\,$1)
|
FixPath = $(subst /,\\,$1)
|
||||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows -DWINDOWS_BUILD
|
CXXFLAGS += -DWINDOWS_BUILD
|
||||||
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
CXXFLAGS_DEBUG += -DWINDOWS_BUILD
|
||||||
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
|
LDFLAGS += -Wl,--gc-sections -static-libstdc++ -static-libgcc \
|
||||||
RM := del /Q
|
-Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows \
|
||||||
|
-lmingw32 -lws2_32 -lSDL3 -lSDL3_ttf
|
||||||
|
RMFILE := del /Q
|
||||||
|
RMDIR := rmdir /S /Q
|
||||||
MKDIR := mkdir
|
MKDIR := mkdir
|
||||||
else
|
else
|
||||||
FixPath = $1
|
FixPath = $1
|
||||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections
|
LDFLAGS += -lSDL3 -lSDL3_ttf
|
||||||
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG
|
|
||||||
LDFLAGS := -lSDL3
|
|
||||||
RMFILE := rm -f
|
RMFILE := rm -f
|
||||||
RMDIR := rm -rdf
|
RMDIR := rm -rf
|
||||||
MKDIR := mkdir -p
|
MKDIR := mkdir -p
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
CXXFLAGS += -DLINUX_BUILD
|
CXXFLAGS += -DLINUX_BUILD
|
||||||
LDFLAGS += -lGL
|
CXXFLAGS_DEBUG += -DLINUX_BUILD
|
||||||
endif
|
endif
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
CXXFLAGS += -Wno-deprecated -DMACOS_BUILD
|
CXXFLAGS += -DMACOS_BUILD -arch arm64
|
||||||
CXXFLAGS_DEBUG += -Wno-deprecated -DMACOS_BUILD
|
CXXFLAGS_DEBUG += -DMACOS_BUILD -arch arm64
|
||||||
LDFLAGS += -framework OpenGL
|
# Si quieres binarios universales:
|
||||||
# Configurar arquitectura (por defecto arm64, como en CMake)
|
# CXXFLAGS += -arch x86_64
|
||||||
CXXFLAGS += -arch arm64
|
# CXXFLAGS_DEBUG += -arch x86_64
|
||||||
CXXFLAGS_DEBUG += -arch arm64
|
# Y frameworks si hacen falta:
|
||||||
|
# LDFLAGS += -framework Cocoa -framework IOKit
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Reglas para herramienta de empaquetado y resources.pack
|
# Reglas para herramienta de empaquetado y resources.pack
|
||||||
$(PACK_TOOL): $(PACK_SOURCES)
|
$(PACK_TOOL): $(PACK_SOURCES)
|
||||||
@echo "Compilando herramienta de empaquetado..."
|
@echo "Compilando herramienta de empaquetado..."
|
||||||
@@ -108,11 +113,21 @@ $(PACK_TOOL): $(PACK_SOURCES)
|
|||||||
|
|
||||||
pack_tool: $(PACK_TOOL)
|
pack_tool: $(PACK_TOOL)
|
||||||
|
|
||||||
resources.pack: $(PACK_TOOL)
|
# Detectar todos los archivos en data/ como dependencias (regenera si cualquiera cambia)
|
||||||
|
DATA_FILES := $(shell find data -type f 2>/dev/null)
|
||||||
|
|
||||||
|
resources.pack: $(PACK_TOOL) $(DATA_FILES)
|
||||||
@echo "Generando resources.pack desde directorio data/..."
|
@echo "Generando resources.pack desde directorio data/..."
|
||||||
$(PACK_TOOL) data resources.pack
|
$(PACK_TOOL) data resources.pack
|
||||||
@echo "✓ resources.pack generado exitosamente"
|
@echo "✓ resources.pack generado exitosamente"
|
||||||
|
|
||||||
|
# Target para forzar regeneración de resources.pack (usado por releases)
|
||||||
|
.PHONY: force_resource_pack
|
||||||
|
force_resource_pack: $(PACK_TOOL)
|
||||||
|
@echo "Regenerando resources.pack para release..."
|
||||||
|
$(PACK_TOOL) data resources.pack
|
||||||
|
@echo "✓ resources.pack regenerado exitosamente"
|
||||||
|
|
||||||
# Reglas para compilación
|
# Reglas para compilación
|
||||||
windows:
|
windows:
|
||||||
@echo off
|
@echo off
|
||||||
@@ -131,20 +146,20 @@ windows_debug:
|
|||||||
@echo Compilando version debug para Windows: "$(APP_NAME)_debug.exe"
|
@echo Compilando version debug para Windows: "$(APP_NAME)_debug.exe"
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(WIN_TARGET_FILE)_debug.exe"
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(WIN_TARGET_FILE)_debug.exe"
|
||||||
|
|
||||||
windows_release: resources.pack
|
windows_release: force_resource_pack
|
||||||
@echo "Creando release para Windows - Version: $(VERSION)"
|
@echo "Creando release para Windows - Version: $(VERSION)"
|
||||||
|
|
||||||
# Crea carpeta temporal 'RELEASE_FOLDER'
|
# Crea carpeta temporal 'RELEASE_FOLDER'
|
||||||
@rm -rf "$(RELEASE_FOLDER)"
|
@if exist "$(RELEASE_FOLDER)" rmdir /S /Q "$(RELEASE_FOLDER)"
|
||||||
@mkdir -p "$(RELEASE_FOLDER)"
|
@mkdir "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
# Copia el archivo 'resources.pack'
|
# Copia el archivo 'resources.pack'
|
||||||
@cp -f "resources.pack" "$(RELEASE_FOLDER)/"
|
@copy /Y "resources.pack" "$(RELEASE_FOLDER)\" >nul
|
||||||
|
|
||||||
# Copia los ficheros que estan en la raíz del proyecto
|
# Copia los ficheros que estan en la raíz del proyecto
|
||||||
@cp -f "LICENSE" "$(RELEASE_FOLDER)/" 2>/dev/null || echo "LICENSE not found (optional)"
|
@copy /Y "LICENSE" "$(RELEASE_FOLDER)\" >nul 2>&1 || echo LICENSE not found (optional)
|
||||||
@cp -f "README.md" "$(RELEASE_FOLDER)/"
|
@copy /Y "README.md" "$(RELEASE_FOLDER)\" >nul
|
||||||
@cp -f release/*.dll "$(RELEASE_FOLDER)/" 2>/dev/null || echo "No DLL files found (optional)"
|
@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)
|
||||||
@@ -152,12 +167,12 @@ windows_release: resources.pack
|
|||||||
@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
|
||||||
@rm -f "$(WINDOWS_RELEASE)"
|
@if exist "$(WINDOWS_RELEASE)" del /Q "$(WINDOWS_RELEASE)"
|
||||||
@powershell.exe -Command "Compress-Archive -Path '$(RELEASE_FOLDER)/*' -DestinationPath '$(WINDOWS_RELEASE)' -Force"
|
@powershell.exe -Command "Compress-Archive -Path '$(RELEASE_FOLDER)/*' -DestinationPath '$(WINDOWS_RELEASE)' -Force"
|
||||||
@echo "Release creado: $(WINDOWS_RELEASE)"
|
@echo "Release creado: $(WINDOWS_RELEASE)"
|
||||||
|
|
||||||
# Elimina la carpeta temporal 'RELEASE_FOLDER'
|
# Elimina la carpeta temporal 'RELEASE_FOLDER'
|
||||||
@rm -rf "$(RELEASE_FOLDER)"
|
@rmdir /S /Q "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
@echo "Compilando para macOS: $(TARGET_NAME)"
|
@echo "Compilando para macOS: $(TARGET_NAME)"
|
||||||
@@ -167,15 +182,24 @@ macos_debug:
|
|||||||
@echo "Compilando version debug para macOS: $(TARGET_NAME)_debug"
|
@echo "Compilando version debug para macOS: $(TARGET_NAME)_debug"
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
||||||
|
|
||||||
macos_release: resources.pack
|
macos_release: force_resource_pack
|
||||||
@echo "Creando release para macOS - Version: $(VERSION)"
|
@echo "Creando release para macOS - Version: $(VERSION)"
|
||||||
|
|
||||||
|
# Verificar e instalar create-dmg si es necesario
|
||||||
|
@which create-dmg > /dev/null || (echo "Instalando create-dmg..." && brew install create-dmg)
|
||||||
|
|
||||||
# Elimina datos de compilaciones anteriores
|
# Elimina datos de compilaciones anteriores
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
$(RMDIR) Frameworks
|
$(RMDIR) Frameworks
|
||||||
$(RMFILE) tmp.dmg
|
|
||||||
$(RMFILE) "$(MACOS_INTEL_RELEASE)"
|
$(RMFILE) "$(MACOS_INTEL_RELEASE)"
|
||||||
$(RMFILE) "$(MACOS_APPLE_SILICON_RELEASE)"
|
$(RMFILE) "$(MACOS_APPLE_SILICON_RELEASE)"
|
||||||
|
|
||||||
|
# Limpia archivos temporales de create-dmg y desmonta volúmenes
|
||||||
|
@echo "Limpiando archivos temporales y volúmenes montados..."
|
||||||
|
@rm -f rw.*.dmg 2>/dev/null || true
|
||||||
|
@hdiutil detach "/Volumes/$(APP_NAME)" 2>/dev/null || true
|
||||||
|
@hdiutil detach "/Volumes/ViBe3 Physics" 2>/dev/null || true
|
||||||
|
|
||||||
# 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"
|
||||||
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
|
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
|
||||||
@@ -185,40 +209,76 @@ macos_release: resources.pack
|
|||||||
# Copia carpetas y ficheros
|
# Copia carpetas y ficheros
|
||||||
cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||||
|
cp -R release/frameworks/SDL3_ttf.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||||
cp -R release/frameworks/SDL3.xcframework Frameworks
|
cp -R release/frameworks/SDL3.xcframework Frameworks
|
||||||
|
cp -R release/frameworks/SDL3_ttf.xcframework Frameworks
|
||||||
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
cp release/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents"
|
cp release/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents"
|
||||||
cp LICENSE "$(RELEASE_FOLDER)"
|
cp LICENSE "$(RELEASE_FOLDER)"
|
||||||
cp README.md "$(RELEASE_FOLDER)"
|
cp README.md "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
# Crea enlaces
|
# NOTA: create-dmg crea automáticamente el enlace a /Applications con --app-drop-link
|
||||||
ln -s /Applications "$(RELEASE_FOLDER)"/Applications
|
# No es necesario crearlo manualmente aquí
|
||||||
|
|
||||||
# Compila la versión para procesadores Intel
|
# Compila la versión para procesadores Intel
|
||||||
ifdef ENABLE_MACOS_X86_64
|
ifdef ENABLE_MACOS_X86_64
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DMACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.15
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DMACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos12
|
||||||
|
|
||||||
# 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"
|
||||||
|
|
||||||
# Empaqueta el .dmg de la versión Intel
|
# Empaqueta el .dmg de la versión Intel con create-dmg
|
||||||
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
|
@echo "Creando DMG Intel con iconos de 96x96..."
|
||||||
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)"
|
@create-dmg \
|
||||||
$(RMFILE) tmp.dmg
|
--volname "$(APP_NAME)" \
|
||||||
@echo "Release Intel creado: $(MACOS_INTEL_RELEASE)"
|
--window-pos 200 120 \
|
||||||
|
--window-size 720 300 \
|
||||||
|
--icon-size 96 \
|
||||||
|
--text-size 12 \
|
||||||
|
--icon "$(APP_NAME).app" 278 102 \
|
||||||
|
--icon "LICENSE" 441 102 \
|
||||||
|
--icon "README.md" 604 102 \
|
||||||
|
--app-drop-link 115 102 \
|
||||||
|
--hide-extension "$(APP_NAME).app" \
|
||||||
|
"$(MACOS_INTEL_RELEASE)" \
|
||||||
|
"$(RELEASE_FOLDER)"
|
||||||
|
@if [ -f "$(MACOS_INTEL_RELEASE)" ]; then \
|
||||||
|
echo "✓ Release Intel creado exitosamente: $(MACOS_INTEL_RELEASE)"; \
|
||||||
|
else \
|
||||||
|
echo "✗ Error: No se pudo crear el DMG Intel"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@rm -f rw.*.dmg 2>/dev/null || true
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Compila la versión para procesadores Apple Silicon
|
# Compila la versión para procesadores Apple Silicon
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DMACOS_BUNDLE -DSDL_DISABLE_IMMINTRIN_H $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DMACOS_BUNDLE -DSDL_DISABLE_IMMINTRIN_H $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos12
|
||||||
|
|
||||||
# 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"
|
||||||
|
|
||||||
# Empaqueta el .dmg de la versión Apple Silicon
|
# Empaqueta el .dmg de la versión Apple Silicon con create-dmg
|
||||||
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
|
@echo "Creando DMG Apple Silicon con iconos de 96x96..."
|
||||||
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)"
|
@create-dmg \
|
||||||
$(RMFILE) tmp.dmg
|
--volname "$(APP_NAME)" \
|
||||||
@echo "Release Apple Silicon creado: $(MACOS_APPLE_SILICON_RELEASE)"
|
--window-pos 200 120 \
|
||||||
|
--window-size 720 300 \
|
||||||
|
--icon-size 96 \
|
||||||
|
--text-size 12 \
|
||||||
|
--icon "$(APP_NAME).app" 278 102 \
|
||||||
|
--icon "LICENSE" 441 102 \
|
||||||
|
--icon "README.md" 604 102 \
|
||||||
|
--app-drop-link 115 102 \
|
||||||
|
--hide-extension "$(APP_NAME).app" \
|
||||||
|
"$(MACOS_APPLE_SILICON_RELEASE)" \
|
||||||
|
"$(RELEASE_FOLDER)"
|
||||||
|
@if [ -f "$(MACOS_APPLE_SILICON_RELEASE)" ]; then \
|
||||||
|
echo "✓ Release Apple Silicon creado exitosamente: $(MACOS_APPLE_SILICON_RELEASE)"; \
|
||||||
|
else \
|
||||||
|
echo "✗ Error: No se pudo crear el DMG Apple Silicon"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@rm -f rw.*.dmg 2>/dev/null || true
|
||||||
|
|
||||||
# Elimina las carpetas temporales
|
# Elimina las carpetas temporales
|
||||||
$(RMDIR) Frameworks
|
$(RMDIR) Frameworks
|
||||||
@@ -233,7 +293,7 @@ linux_debug:
|
|||||||
@echo "Compilando version debug para Linux: $(TARGET_NAME)_debug"
|
@echo "Compilando version debug para Linux: $(TARGET_NAME)_debug"
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
||||||
|
|
||||||
linux_release: resources.pack
|
linux_release: force_resource_pack
|
||||||
@echo "Creando release para Linux - Version: $(VERSION)"
|
@echo "Creando release para Linux - Version: $(VERSION)"
|
||||||
# Elimina carpetas previas
|
# Elimina carpetas previas
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
@@ -258,7 +318,7 @@ linux_release: resources.pack
|
|||||||
# Elimina la carpeta temporal
|
# Elimina la carpeta temporal
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
linux_release_desktop: resources.pack
|
linux_release_desktop: force_resource_pack
|
||||||
@echo "Creando release con integracion desktop para Linux - Version: $(VERSION)"
|
@echo "Creando release con integracion desktop para Linux - Version: $(VERSION)"
|
||||||
# Elimina carpetas previas
|
# Elimina carpetas previas
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
@@ -362,7 +422,7 @@ raspi_debug:
|
|||||||
@echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_debug"
|
@echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_debug"
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE -DDEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE -DDEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
||||||
|
|
||||||
raspi_release: resources.pack
|
raspi_release: force_resource_pack
|
||||||
@echo "Creando release para Raspberry Pi - Version: $(VERSION)"
|
@echo "Creando release para Raspberry Pi - Version: $(VERSION)"
|
||||||
# Elimina carpetas previas
|
# Elimina carpetas previas
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
@@ -387,7 +447,7 @@ raspi_release: resources.pack
|
|||||||
# Elimina la carpeta temporal
|
# Elimina la carpeta temporal
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
anbernic: resources.pack
|
anbernic: force_resource_pack
|
||||||
@echo "Compilando para Anbernic: $(TARGET_NAME)"
|
@echo "Compilando para Anbernic: $(TARGET_NAME)"
|
||||||
# Elimina carpetas previas
|
# Elimina carpetas previas
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
|
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
|
||||||
@@ -426,6 +486,7 @@ help:
|
|||||||
@echo " macos_release - Crear release completo para macOS (.dmg)"
|
@echo " macos_release - Crear release completo para macOS (.dmg)"
|
||||||
@echo " pack_tool - Compilar herramienta de empaquetado"
|
@echo " pack_tool - Compilar herramienta de empaquetado"
|
||||||
@echo " resources.pack - Generar pack de recursos desde data/"
|
@echo " resources.pack - Generar pack de recursos desde data/"
|
||||||
|
@echo " force_resource_pack - Regenerar resources.pack (usado por releases)"
|
||||||
@echo " show_version - Mostrar version actual ($(VERSION))"
|
@echo " show_version - Mostrar version actual ($(VERSION))"
|
||||||
@echo " help - Mostrar esta ayuda"
|
@echo " help - Mostrar esta ayuda"
|
||||||
|
|
||||||
|
|||||||
339
ROADMAP.md
339
ROADMAP.md
@@ -1,339 +0,0 @@
|
|||||||
# ROADMAP - ViBe3 Physics
|
|
||||||
|
|
||||||
## Estado Actual ✅
|
|
||||||
|
|
||||||
### Figuras 3D (8/8 Completadas)
|
|
||||||
- ✅ Q - SPHERE (Esfera Fibonacci)
|
|
||||||
- ✅ W - WAVE_GRID (Malla ondeante) - ⚠️ Necesita mejora de movimiento
|
|
||||||
- ✅ E - HELIX (Espiral helicoidal)
|
|
||||||
- ✅ R - TORUS (Toroide/donut)
|
|
||||||
- ✅ T - CUBE (Cubo rotante)
|
|
||||||
- ✅ Y - CYLINDER (Cilindro) - ⚠️ Necesita rotación multi-eje
|
|
||||||
- ✅ U - ICOSAHEDRON (Icosaedro D20)
|
|
||||||
- ✅ I - ATOM (Núcleo + órbitas)
|
|
||||||
|
|
||||||
### Temas Visuales (7/7 Completadas)
|
|
||||||
- ✅ SUNSET (Atardecer)
|
|
||||||
- ✅ OCEAN (Océano)
|
|
||||||
- ✅ NEON (Neón vibrante)
|
|
||||||
- ✅ FOREST (Bosque)
|
|
||||||
- ✅ RGB (Círculo cromático matemático)
|
|
||||||
- ✅ MONOCHROME (Monocromo - blanco puro)
|
|
||||||
- ✅ LAVENDER (Lavanda - degradado violeta-azul, pelotas doradas)
|
|
||||||
|
|
||||||
### Sistemas de Presentación
|
|
||||||
- ✅ Transiciones LERP entre temas (0.5s suaves)
|
|
||||||
- ✅ Carga dinámica de texturas desde data/balls/
|
|
||||||
- ✅ Hot-swap de sprites con tecla N (cicla entre todas las texturas)
|
|
||||||
- ✅ PNG_SHAPE (O) - Logo "JAILGAMES" con rotación legible
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Mejoras de Presentación 🎨
|
|
||||||
|
|
||||||
### 1. ✅ Mejorar Animaciones de Figuras 3D
|
|
||||||
**Descripción:** Añadir movimientos más dinámicos e interesantes a algunas figuras
|
|
||||||
**Prioridad:** Media
|
|
||||||
**Estado:** ✅ COMPLETADO
|
|
||||||
**Detalles:**
|
|
||||||
|
|
||||||
#### CYLINDER (Y):
|
|
||||||
- ✅ **Rotación principal en eje Y** (spin horizontal continuo)
|
|
||||||
- ✅ **Tumbling ocasional en eje X** cada 3-5 segundos
|
|
||||||
- ✅ Transiciones suaves con ease-in-out (1.5s duración)
|
|
||||||
- ✅ Efecto visual: cilindro "se da una vuelta" ocasionalmente
|
|
||||||
|
|
||||||
#### WAVE_GRID (W):
|
|
||||||
- ✅ **Vista frontal paralela a pantalla** (sin rotación confusa)
|
|
||||||
- ✅ **Pivoteo sutil en ejes X e Y**
|
|
||||||
- ✅ Esquinas se mueven adelante/atrás según posición
|
|
||||||
- ✅ Movimiento ondulatorio + pivoteo = efecto "océano"
|
|
||||||
- ✅ Velocidades lentas (0.3-0.5 rad/s) para organicidad
|
|
||||||
|
|
||||||
### 2. ✅ Modo DEMO (Auto-play)
|
|
||||||
**Descripción:** Modo demostración automática con acciones aleatorias
|
|
||||||
**Prioridad:** Alta
|
|
||||||
**Estado:** ✅ COMPLETADO
|
|
||||||
**Detalles:**
|
|
||||||
- ✅ Toggle con tecla `D`
|
|
||||||
- ✅ Timer que ejecuta acciones cada 3-8 segundos (configurable)
|
|
||||||
- ✅ Acciones: gravedad, figuras, temas, escenarios, impulso, profundidad, escala, sprite
|
|
||||||
- ✅ Secuencia pseudo-aleatoria con pesos configurables (defines.h)
|
|
||||||
- ✅ Totalmente interactivo - usuario puede seguir usando controles
|
|
||||||
- ✅ Indicador visual "DEMO MODE" centrado en pantalla (naranja)
|
|
||||||
- ✅ Eliminado sistema auto-restart antiguo (ya no necesario)
|
|
||||||
|
|
||||||
### 3. ✅ Resolución Lógica Configurable
|
|
||||||
**Descripción:** Especificar resolución lógica por parámetros de línea de comandos
|
|
||||||
**Prioridad:** Media
|
|
||||||
**Estado:** ✅ COMPLETADO
|
|
||||||
**Detalles:**
|
|
||||||
- ✅ Parámetros `-w/--width <px>` y `-h/--height <px>`
|
|
||||||
- ✅ Parámetro `-f/--fullscreen` para pantalla completa
|
|
||||||
- ✅ Defaults: 1280x720 en ventana (si no se especifica)
|
|
||||||
- ✅ Validación: mínimo 640x480
|
|
||||||
- ✅ Help text con `--help`
|
|
||||||
- Ejemplo: `./vibe3_physics -w 1920 -h 1080 -f`
|
|
||||||
|
|
||||||
### 4. ✅ Implementar Modo Logo (Easter Egg)
|
|
||||||
**Descripción:** Modo especial que muestra el logo JAILGAMES como "marca de agua"
|
|
||||||
**Prioridad:** Alta (característica distintiva)
|
|
||||||
**Estado:** ✅ COMPLETADO
|
|
||||||
**Detalles:**
|
|
||||||
|
|
||||||
#### ✅ Configuración Modo Logo:
|
|
||||||
- ✅ **Figura:** Solo PNG_SHAPE (logo JAILGAMES)
|
|
||||||
- ✅ **Textura:** Siempre "tiny" (pelota más pequeña)
|
|
||||||
- ✅ **Tema:** Siempre MONOCHROME (blanco puro)
|
|
||||||
- ✅ **Escala:** 120% (figuras más grandes que normal)
|
|
||||||
- ✅ **Pelotas mínimas:** 500
|
|
||||||
- ✅ **Tecla manual:** K (activa/desactiva modo logo)
|
|
||||||
|
|
||||||
#### ✅ Comportamiento en Modo Logo:
|
|
||||||
- ✅ Alterna entre modo SHAPE y modo PHYSICS (como DEMO)
|
|
||||||
- ✅ Mantiene configuración fija (no cambia tema/textura/escala)
|
|
||||||
- ✅ Es como un "DEMO específico del logo"
|
|
||||||
|
|
||||||
#### ✅ Integración con DEMO LITE:
|
|
||||||
- ✅ **Requisitos para salto automático:**
|
|
||||||
- Mínimo 500 pelotas
|
|
||||||
- Tema MONOCHROME activo
|
|
||||||
- Si se cumplen → cambia automáticamente textura a "tiny" y escala a 120%
|
|
||||||
- ✅ **Duración:** Menos tiempo que DEMO normal (es un "recordatorio")
|
|
||||||
- ✅ **Después:** Vuelve a DEMO LITE normal
|
|
||||||
|
|
||||||
#### ✅ Integración con DEMO:
|
|
||||||
- ✅ **Requisitos:** Mínimo 500 pelotas
|
|
||||||
- ✅ **Acción:** Cambia automáticamente a: MONOCHROME + tiny + escala 120%
|
|
||||||
- ✅ **Duración:** Menos tiempo que acciones normales
|
|
||||||
- ✅ **Después:** Vuelve a DEMO normal
|
|
||||||
|
|
||||||
#### ✅ Proporción temporal sugerida:
|
|
||||||
- ✅ DEMO/DEMO_LITE normal: 80-90% del tiempo
|
|
||||||
- ✅ Modo Logo: 10-20% del tiempo (aparición ocasional como "easter egg")
|
|
||||||
|
|
||||||
### 5. ⏳ Mejorar Sistema de Vértices PNG_SHAPE
|
|
||||||
**Descripción:** Con 50 pelotas no activa modo vértices correctamente
|
|
||||||
**Prioridad:** Baja (mejora visual)
|
|
||||||
**Estimación:** 1 hora
|
|
||||||
**Detalles:**
|
|
||||||
- **Comportamiento actual:** Con 50 pelotas usa filas alternas en bordes
|
|
||||||
- **Comportamiento deseado:** Activar modo VÉRTICES (extremos izq/der de cada fila)
|
|
||||||
- **Problema:** Condición `num_points < 150` no es suficientemente agresiva
|
|
||||||
- **Solución propuesta:**
|
|
||||||
- Ajustar umbrales de activación de vértices
|
|
||||||
- Mejorar algoritmo extractCornerVertices() para detectar puntos clave
|
|
||||||
- Considerar densidad de píxeles en decisión (no solo cantidad absoluta)
|
|
||||||
|
|
||||||
### 5. 🐛 Corregir Escalado de Pelotas en Reposo
|
|
||||||
**Descripción:** Las pelotas cambian de tamaño cuando están quietas (bug visual)
|
|
||||||
**Prioridad:** Alta (bug visible)
|
|
||||||
**Estimación:** 30 minutos
|
|
||||||
**Detalles:**
|
|
||||||
- **Síntoma:** Pelotas en reposo (velocidad ≈ 0) se escalan incorrectamente
|
|
||||||
- **Posible causa:**
|
|
||||||
- Scale factor calculado desde velocidad o energía
|
|
||||||
- División por cero o valor muy pequeño
|
|
||||||
- Interpolación incorrecta en modo transición
|
|
||||||
- **Investigar:** Ball::render(), scale calculations, depth brightness
|
|
||||||
- **Solución esperada:** Tamaño constante independiente de velocidad
|
|
||||||
|
|
||||||
### 6. ✅ Sistema de Release
|
|
||||||
**Descripción:** Empaquetado para distribución standalone
|
|
||||||
**Prioridad:** Baja
|
|
||||||
**Estimación:** 30 minutos
|
|
||||||
**Estado:** ✅ COMPLETADO
|
|
||||||
**Detalles:**
|
|
||||||
- ✅ Carpeta `release/` con recursos
|
|
||||||
- ✅ ResourcePack sistema de empaquetado binario (VBE3 format)
|
|
||||||
- ✅ Tool `pack_resources` para generar resources.pack
|
|
||||||
- ✅ SDL3.dll incluido en release
|
|
||||||
- ✅ Carga híbrida: resources.pack con fallback a data/
|
|
||||||
- ✅ Target `make windows_release` en Makefile
|
|
||||||
- ✅ ZIP generado: vibe3_physics-YYYY-MM-DD-win32-x64.zip
|
|
||||||
|
|
||||||
### 7. ⏳ Logo/Autor Sobreimpreso (Watermark)
|
|
||||||
**Descripción:** Mostrar logo JAILGAMES en esquina con animación periódica
|
|
||||||
**Prioridad:** Media
|
|
||||||
**Estimación:** 2 horas
|
|
||||||
**Detalles:**
|
|
||||||
- **Posición:** Esquina inferior derecha (o configurable)
|
|
||||||
- **Aparición:** Cada X segundos (ej: cada 30-60s)
|
|
||||||
- **Animación entrada:** Fade-in + slide desde fuera de pantalla
|
|
||||||
- **Duración visible:** 3-5 segundos
|
|
||||||
- **Animación salida:** Fade-out + slide hacia fuera
|
|
||||||
- **Rendering:** Textura PNG con alpha blending
|
|
||||||
- **Configuración:**
|
|
||||||
- Intervalo de aparición (LOGO_WATERMARK_INTERVAL)
|
|
||||||
- Duración visible (LOGO_WATERMARK_DURATION)
|
|
||||||
- Tamaño relativo a pantalla (ej: 10-15% ancho)
|
|
||||||
- Opacidad máxima (ej: 70-80% alpha)
|
|
||||||
- **Integración:** No interfiere con debug display ni modos DEMO/LOGO
|
|
||||||
- **Asset:** Reutilizar data/jailgames_logo.png existente
|
|
||||||
|
|
||||||
### 8. ⏳ Mejorar Sistema de Renderizado de Texto
|
|
||||||
**Descripción:** Actualizar tipografía y mejorar clase dbgtxt para mejor legibilidad
|
|
||||||
**Prioridad:** Media
|
|
||||||
**Estimación:** 3-4 horas
|
|
||||||
**Detalles:**
|
|
||||||
- **Problemas actuales:**
|
|
||||||
- Fuente bitmap actual poco legible en resoluciones altas
|
|
||||||
- Sistema dbgtxt limitado (solo fuente fija)
|
|
||||||
- Sin suavizado (aliasing visible)
|
|
||||||
- Tamaño no escala con resolución
|
|
||||||
- **Soluciones propuestas:**
|
|
||||||
- **Opción A - SDL_ttf:** Usar fuentes TrueType (.ttf)
|
|
||||||
- Mayor calidad y escalabilidad
|
|
||||||
- Antialiasing nativo
|
|
||||||
- Soporte Unicode completo
|
|
||||||
- Requiere añadir dependencia SDL3_ttf
|
|
||||||
- **Opción B - Bitmap mejorada:** Nueva fuente bitmap de mayor calidad
|
|
||||||
- Sin dependencias adicionales
|
|
||||||
- Textura PNG con caracteres ASCII
|
|
||||||
- Escalado nearest-neighbor para estética pixel-art
|
|
||||||
- Más control sobre aspecto retro
|
|
||||||
- **Mejoras clase dbgtxt:**
|
|
||||||
- Soporte múltiples tamaños (pequeño/normal/grande)
|
|
||||||
- Sombra/outline configurable para mejor contraste
|
|
||||||
- Alineación (izquierda/centro/derecha)
|
|
||||||
- Color y alpha por texto individual
|
|
||||||
- Medición de ancho de texto (para centrado dinámico)
|
|
||||||
- **Assets necesarios:**
|
|
||||||
- Si TTF: Fuente .ttf embebida (ej: Roboto Mono, Source Code Pro)
|
|
||||||
- Si Bitmap: Nueva textura font_atlas.png de mayor resolución
|
|
||||||
- **Retrocompatibilidad:** Mantener API actual de dbgtxt
|
|
||||||
|
|
||||||
### 9. ⏳ Temas Dinámicos (Color Generativo)
|
|
||||||
**Descripción:** Sistema de generación procedural de temas de colores
|
|
||||||
**Prioridad:** Baja
|
|
||||||
**Estimación:** 4-6 horas
|
|
||||||
**Detalles:**
|
|
||||||
- **Objetivos:**
|
|
||||||
- Gradiente de fondo variable (color base + variaciones automáticas)
|
|
||||||
- Color de pelotas variable (monocromático, complementario, análogo, etc.)
|
|
||||||
- Generación algorítmica de paletas armónicas
|
|
||||||
- **Implementación propuesta:**
|
|
||||||
- **HSV Color Space:** Generar paletas en espacio HSV para control intuitivo
|
|
||||||
- Hue (matiz): 0-360° para variación de color
|
|
||||||
- Saturation (saturación): 0-100% para intensidad
|
|
||||||
- Value (brillo): 0-100% para luminosidad
|
|
||||||
- **Esquemas de color:**
|
|
||||||
- Monocromático (un matiz + variaciones de saturación/brillo)
|
|
||||||
- Complementario (matiz opuesto en rueda de color)
|
|
||||||
- Análogo (matices adyacentes ±30°)
|
|
||||||
- Triádico (3 matices equidistantes 120°)
|
|
||||||
- Tetrádico (4 matices en cuadrado/rectángulo)
|
|
||||||
- **Parámetros configurables:**
|
|
||||||
- Base hue (0-360°): Color principal del tema
|
|
||||||
- Saturation range (0-100%): Rango de intensidad
|
|
||||||
- Value range (0-100%): Rango de brillo
|
|
||||||
- Esquema de armonía: mono/complementario/análogo/etc.
|
|
||||||
- Gradiente de fondo: Automático según base hue
|
|
||||||
- **Controles de usuario:**
|
|
||||||
- Tecla G: Generar nuevo tema aleatorio
|
|
||||||
- Tecla Shift+G: Ciclar esquemas de armonía
|
|
||||||
- Guardar temas generados favoritos (slot 8-12)
|
|
||||||
- **Algoritmos:**
|
|
||||||
- **Gradiente de fondo:** Base hue → Variación análoga oscura (fondo inferior)
|
|
||||||
- **Color de pelotas:** Según esquema elegido (complementario para contraste máximo)
|
|
||||||
- **Conversión HSV → RGB:** Algoritmo estándar para SDL rendering
|
|
||||||
- **Ejemplos de temas generados:**
|
|
||||||
- Tema "Cyberpunk": Base cyan (180°) + Complementario magenta (300°)
|
|
||||||
- Tema "Autumn": Base naranja (30°) + Análogo rojo-amarillo
|
|
||||||
- Tema "Ocean Deep": Base azul (240°) + Monocromático variaciones
|
|
||||||
- Tema "Toxic": Base verde lima (120°) + Complementario púrpura
|
|
||||||
- **Persistencia:**
|
|
||||||
- Guardar temas generados en config.ini (opcional)
|
|
||||||
- Teclas 8-9-0 para slots de temas custom
|
|
||||||
- **Compatibilidad:**
|
|
||||||
- No reemplaza temas existentes (1-7)
|
|
||||||
- Modo adicional de selección de tema
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Futuras Mejoras (Ideas)
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
- [ ] Spatial partitioning para colisiones ball-to-ball
|
|
||||||
- [ ] Level-of-detail para 100K+ pelotas
|
|
||||||
- [ ] GPU compute shaders para física masiva
|
|
||||||
|
|
||||||
### Efectos Visuales
|
|
||||||
- [ ] Trails (estelas de movimiento)
|
|
||||||
- [ ] Heatmaps de velocidad/energía
|
|
||||||
- [ ] Bloom/glow para sprites
|
|
||||||
|
|
||||||
### Física Avanzada
|
|
||||||
- [ ] Colisiones entre partículas
|
|
||||||
- [ ] Viento (fuerza horizontal)
|
|
||||||
- [ ] Campos magnéticos (atracción/repulsión)
|
|
||||||
- [ ] Turbulencia
|
|
||||||
|
|
||||||
### Shapes PNG
|
|
||||||
- [ ] **Voxelización 3D para PNG_SHAPE** (Enfoque B)
|
|
||||||
- Actualmente: Extrusión 2D simple (píxeles → capas Z)
|
|
||||||
- Futuro: Voxelización real con detección de interior/exterior
|
|
||||||
- Permite formas 3D más complejas desde imágenes
|
|
||||||
- Rotación volumétrica en vez de extrusión plana
|
|
||||||
|
|
||||||
### Interactividad
|
|
||||||
- [ ] Mouse: click para aplicar fuerzas
|
|
||||||
- [ ] Mouse: drag para crear campos
|
|
||||||
- [ ] Mouse wheel: ajustar intensidad
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Historial de Cambios
|
|
||||||
|
|
||||||
### 2025-10-04 (Sesión 5) - PNG Shape + Texturas Dinámicas + CLI
|
|
||||||
- ✅ **PNG_SHAPE implementado** - Tecla O para activar logo "JAILGAMES"
|
|
||||||
- ✅ Carga de PNG 1-bit con stb_image
|
|
||||||
- ✅ Extrusión 2D (Enfoque A) - píxeles → capas Z
|
|
||||||
- ✅ Detección de bordes vs relleno completo (configurable)
|
|
||||||
- ✅ Tamaño 80% pantalla (como otras figuras)
|
|
||||||
- ✅ Rotación "legible" - De frente con volteretas ocasionales (3-8s idle)
|
|
||||||
- ✅ Fix: Z forzado a máximo cuando está de frente (texto brillante)
|
|
||||||
- ✅ Excluido de DEMO/DEMO_LITE (logo especial)
|
|
||||||
- ✅ **Sistema de texturas dinámicas** - Carga automática desde data/balls/
|
|
||||||
- ✅ Tecla N cicla entre todas las texturas PNG encontradas
|
|
||||||
- ✅ Orden alfabético con normal.png primero por defecto
|
|
||||||
- ✅ Display dinámico del nombre de textura (uppercase)
|
|
||||||
- ✅ **Física mejorada SHAPE** - Constantes separadas de ROTOBALL
|
|
||||||
- ✅ Pegajosidad 2.67x mayor (SPRING_K=800 vs 300)
|
|
||||||
- ✅ Pelotas se adhieren mejor durante rotaciones rápidas
|
|
||||||
- ✅ **Parámetros de línea de comandos** - `-w/-h/-f/--help`
|
|
||||||
- ✅ Resolución configurable (mínimo 640x480)
|
|
||||||
- 📝 Preparado para voxelización 3D (Enfoque B) en futuro
|
|
||||||
|
|
||||||
### 2025-10-04 (Sesión 4) - Modo DEMO + Mejoras Animaciones
|
|
||||||
- ✅ **Implementado Modo DEMO (auto-play)** - Tecla D para toggle
|
|
||||||
- ✅ Sistema de acciones aleatorias cada 3-8 segundos (configurable)
|
|
||||||
- ✅ 8 tipos de acciones con pesos de probabilidad ajustables
|
|
||||||
- ✅ Totalmente interactivo - usuario puede seguir controlando
|
|
||||||
- ✅ Display visual "DEMO MODE" centrado en naranja
|
|
||||||
- ✅ **Mejoras animaciones 3D**: tumbling en cilindro + pivoteo en wave grid
|
|
||||||
- ✅ CYLINDER: tumbling ocasional en eje X cada 3-5s con ease-in-out
|
|
||||||
- ✅ WAVE_GRID: pivoteo sutil paralelo a pantalla (efecto océano)
|
|
||||||
- ❌ Eliminado sistema auto-restart antiguo (ya no necesario)
|
|
||||||
|
|
||||||
### 2025-10-04 (Sesión 3)
|
|
||||||
- ✅ Implementado tema MONOCHROME (6º tema)
|
|
||||||
- ✅ Sistema LERP para transiciones suaves de temas (0.5s)
|
|
||||||
- ✅ Hot-swap de sprites con tecla N (ball.png ↔ ball_small.png)
|
|
||||||
- ✅ Tamaño dinámico de pelotas desde texture->getWidth()
|
|
||||||
- ✅ Ajuste de posiciones inteligente al cambiar sprite
|
|
||||||
- 📝 Añadidas mejoras propuestas para CYLINDER y WAVE_GRID
|
|
||||||
|
|
||||||
### 2025-10-03 (Sesión 2)
|
|
||||||
- ✅ Implementadas 8 figuras 3D (SPHERE, WAVE_GRID, HELIX, TORUS, CUBE, CYLINDER, ICOSAHEDRON, ATOM)
|
|
||||||
- ✅ Sistema polimórfico de shapes con herencia virtual
|
|
||||||
|
|
||||||
### 2025-10-02 (Sesión 1)
|
|
||||||
- ✅ Migración desde vibe1_delta
|
|
||||||
- ✅ Sistema de gravedad direccional (4 direcciones)
|
|
||||||
- ✅ Coeficientes de rebote variables (0.30-0.95)
|
|
||||||
- ✅ 5 temas de colores iniciales
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Última actualización:** 2025-10-04
|
|
||||||
BIN
data/fonts/BBHSansHegarty-Regular.ttf
Normal file
BIN
data/fonts/BBHSansHegarty-Regular.ttf
Normal file
Binary file not shown.
BIN
data/fonts/FunnelSans-Regular.ttf
Normal file
BIN
data/fonts/FunnelSans-Regular.ttf
Normal file
Binary file not shown.
BIN
data/fonts/JetBrainsMono-Regular.ttf
Normal file
BIN
data/fonts/JetBrainsMono-Regular.ttf
Normal file
Binary file not shown.
BIN
data/fonts/Minecraftia-Regular.ttf
Normal file
BIN
data/fonts/Minecraftia-Regular.ttf
Normal file
Binary file not shown.
BIN
data/fonts/PixelOperator.ttf
Normal file
BIN
data/fonts/PixelOperator.ttf
Normal file
Binary file not shown.
BIN
data/fonts/determination.ttf
Normal file
BIN
data/fonts/determination.ttf
Normal file
Binary file not shown.
BIN
data/fonts/dogica.ttf
Normal file
BIN
data/fonts/dogica.ttf
Normal file
Binary file not shown.
BIN
data/fonts/rainyhearts.ttf
Normal file
BIN
data/fonts/rainyhearts.ttf
Normal file
Binary file not shown.
BIN
data/logo/logo.png
Normal file
BIN
data/logo/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
BIN
data/logo/logo2.png
Normal file
BIN
data/logo/logo2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
@@ -29,7 +29,7 @@
|
|||||||
<key>CSResourcesFileMapped</key>
|
<key>CSResourcesFileMapped</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>10.15</string>
|
<string>12.0</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
|||||||
BIN
release/dll/SDL3.dll
Normal file
BIN
release/dll/SDL3.dll
Normal file
Binary file not shown.
BIN
release/dll/SDL3_ttf.dll
Normal file
BIN
release/dll/SDL3_ttf.dll
Normal file
Binary file not shown.
BIN
release/dll/libwinpthread-1.dll
Normal file
BIN
release/dll/libwinpthread-1.dll
Normal file
Binary file not shown.
90
release/frameworks/SDL3_ttf.xcframework/Info.plist
Normal file
90
release/frameworks/SDL3_ttf.xcframework/Info.plist
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>AvailableLibraries</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3_ttf.framework/SDL3_ttf</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>tvos-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3_ttf.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>tvos</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3_ttf.framework/SDL3_ttf</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3_ttf.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3_ttf.framework/SDL3_ttf</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>tvos-arm64_x86_64-simulator</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3_ttf.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>tvos</string>
|
||||||
|
<key>SupportedPlatformVariant</key>
|
||||||
|
<string>simulator</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3_ttf.framework/SDL3_ttf</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>ios-arm64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3_ttf.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>ios</string>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>BinaryPath</key>
|
||||||
|
<string>SDL3_ttf.framework/Versions/A/SDL3_ttf</string>
|
||||||
|
<key>LibraryIdentifier</key>
|
||||||
|
<string>macos-arm64_x86_64</string>
|
||||||
|
<key>LibraryPath</key>
|
||||||
|
<string>SDL3_ttf.framework</string>
|
||||||
|
<key>SupportedArchitectures</key>
|
||||||
|
<array>
|
||||||
|
<string>arm64</string>
|
||||||
|
<string>x86_64</string>
|
||||||
|
</array>
|
||||||
|
<key>SupportedPlatform</key>
|
||||||
|
<string>macos</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>XFWK</string>
|
||||||
|
<key>XCFrameworkFormatVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
|
||||||
|
Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file SDL_textengine.h
|
||||||
|
*
|
||||||
|
* Definitions for implementations of the TTF_TextEngine interface.
|
||||||
|
*/
|
||||||
|
#ifndef SDL_TTF_TEXTENGINE_H_
|
||||||
|
#define SDL_TTF_TEXTENGINE_H_
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A font atlas draw command.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef enum TTF_DrawCommand
|
||||||
|
{
|
||||||
|
TTF_DRAW_COMMAND_NOOP,
|
||||||
|
TTF_DRAW_COMMAND_FILL,
|
||||||
|
TTF_DRAW_COMMAND_COPY
|
||||||
|
} TTF_DrawCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filled rectangle draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_FillOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_FILL */
|
||||||
|
SDL_Rect rect; /**< The rectangle to fill, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
} TTF_FillOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A texture copy draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_CopyOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_COPY */
|
||||||
|
int text_offset; /**< The offset in the text corresponding to this glyph.
|
||||||
|
There may be multiple glyphs with the same text offset
|
||||||
|
and the next text offset might be several Unicode codepoints
|
||||||
|
later. In this case the glyphs and codepoints are grouped
|
||||||
|
together and the group bounding box is the union of the dst
|
||||||
|
rectangles for the corresponding glyphs. */
|
||||||
|
TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
SDL_Rect src; /**< The area within the glyph to be drawn */
|
||||||
|
SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
void *reserved;
|
||||||
|
} TTF_CopyOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef union TTF_DrawOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd;
|
||||||
|
TTF_FillOperation fill;
|
||||||
|
TTF_CopyOperation copy;
|
||||||
|
} TTF_DrawOperation;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, to assist in text measurement and layout */
|
||||||
|
typedef struct TTF_TextLayout TTF_TextLayout;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, available to implementations */
|
||||||
|
struct TTF_TextData
|
||||||
|
{
|
||||||
|
TTF_Font *font; /**< The font used by this text, read-only. */
|
||||||
|
SDL_FColor color; /**< The color of the text, read-only. */
|
||||||
|
|
||||||
|
bool needs_layout_update; /**< True if the layout needs to be updated */
|
||||||
|
TTF_TextLayout *layout; /**< Cached layout information, read-only. */
|
||||||
|
int x; /**< The x offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int y; /**< The y offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int w; /**< The width of this text, in pixels, read-only. */
|
||||||
|
int h; /**< The height of this text, in pixels, read-only. */
|
||||||
|
int num_ops; /**< The number of drawing operations to render this text, read-only. */
|
||||||
|
TTF_DrawOperation *ops; /**< The drawing operations used to render this text, read-only. */
|
||||||
|
int num_clusters; /**< The number of substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
TTF_SubString *clusters; /**< Substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
|
||||||
|
SDL_PropertiesID props; /**< Custom properties associated with this text, read-only. This field is created as-needed using TTF_GetTextProperties() and the properties may be then set and read normally */
|
||||||
|
|
||||||
|
bool needs_engine_update; /**< True if the engine text needs to be updated */
|
||||||
|
TTF_TextEngine *engine; /**< The engine used to render this text, read-only. */
|
||||||
|
void *engine_text; /**< The implementation-specific representation of this text */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine interface.
|
||||||
|
*
|
||||||
|
* This structure should be initialized using SDL_INIT_INTERFACE()
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_INIT_INTERFACE
|
||||||
|
*/
|
||||||
|
struct TTF_TextEngine
|
||||||
|
{
|
||||||
|
Uint32 version; /**< The version of this interface */
|
||||||
|
|
||||||
|
void *userdata; /**< User data pointer passed to callbacks */
|
||||||
|
|
||||||
|
/* Create a text representation from draw instructions.
|
||||||
|
*
|
||||||
|
* All fields of `text` except `internal->engine_text` will already be filled out.
|
||||||
|
*
|
||||||
|
* This function should set the `internal->engine_text` field to a non-NULL value.
|
||||||
|
*
|
||||||
|
* \param userdata the userdata pointer in this interface.
|
||||||
|
* \param text the text object being created.
|
||||||
|
*/
|
||||||
|
bool (SDLCALL *CreateText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a text representation.
|
||||||
|
*/
|
||||||
|
void (SDLCALL *DestroyText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Check the size of TTF_TextEngine
|
||||||
|
*
|
||||||
|
* If this assert fails, either the compiler is padding to an unexpected size,
|
||||||
|
* or the interface has been updated and this should be updated to match and
|
||||||
|
* the code using this interface should be updated to handle the old version.
|
||||||
|
*/
|
||||||
|
SDL_COMPILE_TIME_ASSERT(TTF_TextEngine_SIZE,
|
||||||
|
(sizeof(void *) == 4 && sizeof(TTF_TextEngine) == 16) ||
|
||||||
|
(sizeof(void *) == 8 && sizeof(TTF_TextEngine) == 32));
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_TTF_TEXTENGINE_H_ */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
# Using this package
|
||||||
|
|
||||||
|
This package contains SDL_ttf built for Xcode.
|
||||||
|
|
||||||
|
To use this package in Xcode, drag `SDL3_ttf.framework` into your project.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
An API reference and additional documentation is available at:
|
||||||
|
|
||||||
|
https://wiki.libsdl.org/SDL3_ttf
|
||||||
|
|
||||||
|
# Discussions
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
|
||||||
|
You can join the official Discord server at:
|
||||||
|
|
||||||
|
https://discord.com/invite/BwpFGBWsv8
|
||||||
|
|
||||||
|
## Forums/mailing lists
|
||||||
|
|
||||||
|
You can join SDL development discussions at:
|
||||||
|
|
||||||
|
https://discourse.libsdl.org/
|
||||||
|
|
||||||
|
Once you sign up, you can use the forum through the website or as a mailing list from your email client.
|
||||||
|
|
||||||
|
## Announcement list
|
||||||
|
|
||||||
|
You can sign up for the low traffic announcement list at:
|
||||||
|
|
||||||
|
https://www.libsdl.org/mailing-list.php
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
SDL_ttf 3.0
|
||||||
|
|
||||||
|
This library is a wrapper around the FreeType and Harfbuzz libraries, allowing you to use TrueType fonts to render text in SDL applications.
|
||||||
|
|
||||||
|
The latest version of this library is available from GitHub:
|
||||||
|
https://github.com/libsdl-org/SDL_ttf/releases
|
||||||
|
|
||||||
|
Installation instructions and a quick introduction is available in
|
||||||
|
[INSTALL.md](INSTALL.md)
|
||||||
|
|
||||||
|
This library is distributed under the terms of the zlib license,
|
||||||
|
available in [LICENSE.txt](LICENSE.txt).
|
||||||
|
|
||||||
|
This library also uses the following libraries:
|
||||||
|
- FreeType, licensed under the [FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT)
|
||||||
|
- HarfBuzz, licensed under the [MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING)
|
||||||
|
- PlutoSVG, licensed under the [MIT license](https://github.com/sammycage/plutosvg/blob/master/LICENSE)
|
||||||
|
- PlutoVG, licensed under the [MIT license](https://github.com/sammycage/plutovg/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
Sam Lantinga (slouken@libsdl.org)
|
||||||
BIN
release/frameworks/SDL3_ttf.xcframework/ios-arm64/SDL3_ttf.framework/SDL3_ttf
Executable file
BIN
release/frameworks/SDL3_ttf.xcframework/ios-arm64/SDL3_ttf.framework/SDL3_ttf
Executable file
Binary file not shown.
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
|
||||||
|
Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file SDL_textengine.h
|
||||||
|
*
|
||||||
|
* Definitions for implementations of the TTF_TextEngine interface.
|
||||||
|
*/
|
||||||
|
#ifndef SDL_TTF_TEXTENGINE_H_
|
||||||
|
#define SDL_TTF_TEXTENGINE_H_
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A font atlas draw command.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef enum TTF_DrawCommand
|
||||||
|
{
|
||||||
|
TTF_DRAW_COMMAND_NOOP,
|
||||||
|
TTF_DRAW_COMMAND_FILL,
|
||||||
|
TTF_DRAW_COMMAND_COPY
|
||||||
|
} TTF_DrawCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filled rectangle draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_FillOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_FILL */
|
||||||
|
SDL_Rect rect; /**< The rectangle to fill, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
} TTF_FillOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A texture copy draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_CopyOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_COPY */
|
||||||
|
int text_offset; /**< The offset in the text corresponding to this glyph.
|
||||||
|
There may be multiple glyphs with the same text offset
|
||||||
|
and the next text offset might be several Unicode codepoints
|
||||||
|
later. In this case the glyphs and codepoints are grouped
|
||||||
|
together and the group bounding box is the union of the dst
|
||||||
|
rectangles for the corresponding glyphs. */
|
||||||
|
TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
SDL_Rect src; /**< The area within the glyph to be drawn */
|
||||||
|
SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
void *reserved;
|
||||||
|
} TTF_CopyOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef union TTF_DrawOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd;
|
||||||
|
TTF_FillOperation fill;
|
||||||
|
TTF_CopyOperation copy;
|
||||||
|
} TTF_DrawOperation;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, to assist in text measurement and layout */
|
||||||
|
typedef struct TTF_TextLayout TTF_TextLayout;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, available to implementations */
|
||||||
|
struct TTF_TextData
|
||||||
|
{
|
||||||
|
TTF_Font *font; /**< The font used by this text, read-only. */
|
||||||
|
SDL_FColor color; /**< The color of the text, read-only. */
|
||||||
|
|
||||||
|
bool needs_layout_update; /**< True if the layout needs to be updated */
|
||||||
|
TTF_TextLayout *layout; /**< Cached layout information, read-only. */
|
||||||
|
int x; /**< The x offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int y; /**< The y offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int w; /**< The width of this text, in pixels, read-only. */
|
||||||
|
int h; /**< The height of this text, in pixels, read-only. */
|
||||||
|
int num_ops; /**< The number of drawing operations to render this text, read-only. */
|
||||||
|
TTF_DrawOperation *ops; /**< The drawing operations used to render this text, read-only. */
|
||||||
|
int num_clusters; /**< The number of substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
TTF_SubString *clusters; /**< Substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
|
||||||
|
SDL_PropertiesID props; /**< Custom properties associated with this text, read-only. This field is created as-needed using TTF_GetTextProperties() and the properties may be then set and read normally */
|
||||||
|
|
||||||
|
bool needs_engine_update; /**< True if the engine text needs to be updated */
|
||||||
|
TTF_TextEngine *engine; /**< The engine used to render this text, read-only. */
|
||||||
|
void *engine_text; /**< The implementation-specific representation of this text */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine interface.
|
||||||
|
*
|
||||||
|
* This structure should be initialized using SDL_INIT_INTERFACE()
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_INIT_INTERFACE
|
||||||
|
*/
|
||||||
|
struct TTF_TextEngine
|
||||||
|
{
|
||||||
|
Uint32 version; /**< The version of this interface */
|
||||||
|
|
||||||
|
void *userdata; /**< User data pointer passed to callbacks */
|
||||||
|
|
||||||
|
/* Create a text representation from draw instructions.
|
||||||
|
*
|
||||||
|
* All fields of `text` except `internal->engine_text` will already be filled out.
|
||||||
|
*
|
||||||
|
* This function should set the `internal->engine_text` field to a non-NULL value.
|
||||||
|
*
|
||||||
|
* \param userdata the userdata pointer in this interface.
|
||||||
|
* \param text the text object being created.
|
||||||
|
*/
|
||||||
|
bool (SDLCALL *CreateText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a text representation.
|
||||||
|
*/
|
||||||
|
void (SDLCALL *DestroyText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Check the size of TTF_TextEngine
|
||||||
|
*
|
||||||
|
* If this assert fails, either the compiler is padding to an unexpected size,
|
||||||
|
* or the interface has been updated and this should be updated to match and
|
||||||
|
* the code using this interface should be updated to handle the old version.
|
||||||
|
*/
|
||||||
|
SDL_COMPILE_TIME_ASSERT(TTF_TextEngine_SIZE,
|
||||||
|
(sizeof(void *) == 4 && sizeof(TTF_TextEngine) == 16) ||
|
||||||
|
(sizeof(void *) == 8 && sizeof(TTF_TextEngine) == 32));
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_TTF_TEXTENGINE_H_ */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
# Using this package
|
||||||
|
|
||||||
|
This package contains SDL_ttf built for Xcode.
|
||||||
|
|
||||||
|
To use this package in Xcode, drag `SDL3_ttf.framework` into your project.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
An API reference and additional documentation is available at:
|
||||||
|
|
||||||
|
https://wiki.libsdl.org/SDL3_ttf
|
||||||
|
|
||||||
|
# Discussions
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
|
||||||
|
You can join the official Discord server at:
|
||||||
|
|
||||||
|
https://discord.com/invite/BwpFGBWsv8
|
||||||
|
|
||||||
|
## Forums/mailing lists
|
||||||
|
|
||||||
|
You can join SDL development discussions at:
|
||||||
|
|
||||||
|
https://discourse.libsdl.org/
|
||||||
|
|
||||||
|
Once you sign up, you can use the forum through the website or as a mailing list from your email client.
|
||||||
|
|
||||||
|
## Announcement list
|
||||||
|
|
||||||
|
You can sign up for the low traffic announcement list at:
|
||||||
|
|
||||||
|
https://www.libsdl.org/mailing-list.php
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
SDL_ttf 3.0
|
||||||
|
|
||||||
|
This library is a wrapper around the FreeType and Harfbuzz libraries, allowing you to use TrueType fonts to render text in SDL applications.
|
||||||
|
|
||||||
|
The latest version of this library is available from GitHub:
|
||||||
|
https://github.com/libsdl-org/SDL_ttf/releases
|
||||||
|
|
||||||
|
Installation instructions and a quick introduction is available in
|
||||||
|
[INSTALL.md](INSTALL.md)
|
||||||
|
|
||||||
|
This library is distributed under the terms of the zlib license,
|
||||||
|
available in [LICENSE.txt](LICENSE.txt).
|
||||||
|
|
||||||
|
This library also uses the following libraries:
|
||||||
|
- FreeType, licensed under the [FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT)
|
||||||
|
- HarfBuzz, licensed under the [MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING)
|
||||||
|
- PlutoSVG, licensed under the [MIT license](https://github.com/sammycage/plutosvg/blob/master/LICENSE)
|
||||||
|
- PlutoVG, licensed under the [MIT license](https://github.com/sammycage/plutovg/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
Sam Lantinga (slouken@libsdl.org)
|
||||||
Binary file not shown.
@@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>files</key>
|
||||||
|
<dict>
|
||||||
|
<key>CMake/SDL3_ttfConfig.cmake</key>
|
||||||
|
<data>
|
||||||
|
V6UpWQTvr/puOrlm1sgAs6fktNA=
|
||||||
|
</data>
|
||||||
|
<key>CMake/SDL3_ttfConfigVersion.cmake</key>
|
||||||
|
<data>
|
||||||
|
WW2xmNHZyYr9y3/8uAylJuutcPw=
|
||||||
|
</data>
|
||||||
|
<key>Headers/SDL_textengine.h</key>
|
||||||
|
<data>
|
||||||
|
7QAtKpC/pLIq6TK3F59Ax1hg3tc=
|
||||||
|
</data>
|
||||||
|
<key>Headers/SDL_ttf.h</key>
|
||||||
|
<data>
|
||||||
|
90S4SFzJy1lUuMotaCRWpTbzRa4=
|
||||||
|
</data>
|
||||||
|
<key>INSTALL.md</key>
|
||||||
|
<data>
|
||||||
|
3kA+9HE5dF7+nyypVt5YOfU+Uho=
|
||||||
|
</data>
|
||||||
|
<key>Info.plist</key>
|
||||||
|
<data>
|
||||||
|
9F72T63xvwi9u+kC0p9N011q3IM=
|
||||||
|
</data>
|
||||||
|
<key>LICENSE.txt</key>
|
||||||
|
<data>
|
||||||
|
dp6e8JHkl0CrYD+oe2IXZfWB/iw=
|
||||||
|
</data>
|
||||||
|
<key>README.md</key>
|
||||||
|
<data>
|
||||||
|
lm034L4zWKPElKb9O2dmehurfFQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>files2</key>
|
||||||
|
<dict>
|
||||||
|
<key>CMake/SDL3_ttfConfig.cmake</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
VpwUT/D8TjpLXBguVImWqsMkqni9HXiIzx91C92Krqc=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>CMake/SDL3_ttfConfigVersion.cmake</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
tb1RnDTj72GQOzcXp6FPtiqW8tSD886UyUY09c1Ms/U=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/SDL_textengine.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Uk27FTzsWoYySpKM1gkwCB/svSxscGViuMzca93gLP8=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/SDL_ttf.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
6bsCCUp3Uc3tCp+0Xxw7Tt01+UV8bra5YN1dFjpRBL0=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>INSTALL.md</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Jq9GEmdnFRmUTNnYYZZ+5mFqqrMelD86Gthhyi2kGJQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>LICENSE.txt</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
eCbsoKD35ZHzjdhE4geiAKrIGlmyDYoww6+MYoKvE+Y=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>README.md</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
6aipppbEU7MEd3x9OHnKqAGyFXVYiSAL8X8lm271U00=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>rules</key>
|
||||||
|
<dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version.plist$</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>rules2</key>
|
||||||
|
<dict>
|
||||||
|
<key>.*\.dSYM($|/)</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>11</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(.*/)?\.DS_Store$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>2000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Info\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^PkgInfo$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^embedded\.provisionprofile$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Versions/Current/Headers
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Versions/Current/Resources
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Versions/Current/SDL3_ttf
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
|
||||||
|
Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file SDL_textengine.h
|
||||||
|
*
|
||||||
|
* Definitions for implementations of the TTF_TextEngine interface.
|
||||||
|
*/
|
||||||
|
#ifndef SDL_TTF_TEXTENGINE_H_
|
||||||
|
#define SDL_TTF_TEXTENGINE_H_
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A font atlas draw command.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef enum TTF_DrawCommand
|
||||||
|
{
|
||||||
|
TTF_DRAW_COMMAND_NOOP,
|
||||||
|
TTF_DRAW_COMMAND_FILL,
|
||||||
|
TTF_DRAW_COMMAND_COPY
|
||||||
|
} TTF_DrawCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filled rectangle draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_FillOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_FILL */
|
||||||
|
SDL_Rect rect; /**< The rectangle to fill, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
} TTF_FillOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A texture copy draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_CopyOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_COPY */
|
||||||
|
int text_offset; /**< The offset in the text corresponding to this glyph.
|
||||||
|
There may be multiple glyphs with the same text offset
|
||||||
|
and the next text offset might be several Unicode codepoints
|
||||||
|
later. In this case the glyphs and codepoints are grouped
|
||||||
|
together and the group bounding box is the union of the dst
|
||||||
|
rectangles for the corresponding glyphs. */
|
||||||
|
TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
SDL_Rect src; /**< The area within the glyph to be drawn */
|
||||||
|
SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
void *reserved;
|
||||||
|
} TTF_CopyOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef union TTF_DrawOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd;
|
||||||
|
TTF_FillOperation fill;
|
||||||
|
TTF_CopyOperation copy;
|
||||||
|
} TTF_DrawOperation;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, to assist in text measurement and layout */
|
||||||
|
typedef struct TTF_TextLayout TTF_TextLayout;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, available to implementations */
|
||||||
|
struct TTF_TextData
|
||||||
|
{
|
||||||
|
TTF_Font *font; /**< The font used by this text, read-only. */
|
||||||
|
SDL_FColor color; /**< The color of the text, read-only. */
|
||||||
|
|
||||||
|
bool needs_layout_update; /**< True if the layout needs to be updated */
|
||||||
|
TTF_TextLayout *layout; /**< Cached layout information, read-only. */
|
||||||
|
int x; /**< The x offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int y; /**< The y offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int w; /**< The width of this text, in pixels, read-only. */
|
||||||
|
int h; /**< The height of this text, in pixels, read-only. */
|
||||||
|
int num_ops; /**< The number of drawing operations to render this text, read-only. */
|
||||||
|
TTF_DrawOperation *ops; /**< The drawing operations used to render this text, read-only. */
|
||||||
|
int num_clusters; /**< The number of substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
TTF_SubString *clusters; /**< Substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
|
||||||
|
SDL_PropertiesID props; /**< Custom properties associated with this text, read-only. This field is created as-needed using TTF_GetTextProperties() and the properties may be then set and read normally */
|
||||||
|
|
||||||
|
bool needs_engine_update; /**< True if the engine text needs to be updated */
|
||||||
|
TTF_TextEngine *engine; /**< The engine used to render this text, read-only. */
|
||||||
|
void *engine_text; /**< The implementation-specific representation of this text */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine interface.
|
||||||
|
*
|
||||||
|
* This structure should be initialized using SDL_INIT_INTERFACE()
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_INIT_INTERFACE
|
||||||
|
*/
|
||||||
|
struct TTF_TextEngine
|
||||||
|
{
|
||||||
|
Uint32 version; /**< The version of this interface */
|
||||||
|
|
||||||
|
void *userdata; /**< User data pointer passed to callbacks */
|
||||||
|
|
||||||
|
/* Create a text representation from draw instructions.
|
||||||
|
*
|
||||||
|
* All fields of `text` except `internal->engine_text` will already be filled out.
|
||||||
|
*
|
||||||
|
* This function should set the `internal->engine_text` field to a non-NULL value.
|
||||||
|
*
|
||||||
|
* \param userdata the userdata pointer in this interface.
|
||||||
|
* \param text the text object being created.
|
||||||
|
*/
|
||||||
|
bool (SDLCALL *CreateText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a text representation.
|
||||||
|
*/
|
||||||
|
void (SDLCALL *DestroyText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Check the size of TTF_TextEngine
|
||||||
|
*
|
||||||
|
* If this assert fails, either the compiler is padding to an unexpected size,
|
||||||
|
* or the interface has been updated and this should be updated to match and
|
||||||
|
* the code using this interface should be updated to handle the old version.
|
||||||
|
*/
|
||||||
|
SDL_COMPILE_TIME_ASSERT(TTF_TextEngine_SIZE,
|
||||||
|
(sizeof(void *) == 4 && sizeof(TTF_TextEngine) == 16) ||
|
||||||
|
(sizeof(void *) == 8 && sizeof(TTF_TextEngine) == 32));
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_TTF_TEXTENGINE_H_ */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
# Using this package
|
||||||
|
|
||||||
|
This package contains SDL_ttf built for Xcode.
|
||||||
|
|
||||||
|
To use this package in Xcode, drag `SDL3_ttf.framework` into your project.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
An API reference and additional documentation is available at:
|
||||||
|
|
||||||
|
https://wiki.libsdl.org/SDL3_ttf
|
||||||
|
|
||||||
|
# Discussions
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
|
||||||
|
You can join the official Discord server at:
|
||||||
|
|
||||||
|
https://discord.com/invite/BwpFGBWsv8
|
||||||
|
|
||||||
|
## Forums/mailing lists
|
||||||
|
|
||||||
|
You can join SDL development discussions at:
|
||||||
|
|
||||||
|
https://discourse.libsdl.org/
|
||||||
|
|
||||||
|
Once you sign up, you can use the forum through the website or as a mailing list from your email client.
|
||||||
|
|
||||||
|
## Announcement list
|
||||||
|
|
||||||
|
You can sign up for the low traffic announcement list at:
|
||||||
|
|
||||||
|
https://www.libsdl.org/mailing-list.php
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>BuildMachineOSBuild</key>
|
||||||
|
<string>23H420</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>SDL3_ttf</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>org.libsdl.SDL3-ttf</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>SDL3_ttf</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>3.2.2</string>
|
||||||
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
|
<array>
|
||||||
|
<string>MacOSX</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>3.2.2</string>
|
||||||
|
<key>DTCompiler</key>
|
||||||
|
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||||
|
<key>DTPlatformBuild</key>
|
||||||
|
<string></string>
|
||||||
|
<key>DTPlatformName</key>
|
||||||
|
<string>macosx</string>
|
||||||
|
<key>DTPlatformVersion</key>
|
||||||
|
<string>14.5</string>
|
||||||
|
<key>DTSDKBuild</key>
|
||||||
|
<string>23F73</string>
|
||||||
|
<key>DTSDKName</key>
|
||||||
|
<string>macosx14.5</string>
|
||||||
|
<key>DTXcode</key>
|
||||||
|
<string>1540</string>
|
||||||
|
<key>DTXcodeBuild</key>
|
||||||
|
<string>15F31d</string>
|
||||||
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
<string>10.13</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
SDL_ttf 3.0
|
||||||
|
|
||||||
|
This library is a wrapper around the FreeType and Harfbuzz libraries, allowing you to use TrueType fonts to render text in SDL applications.
|
||||||
|
|
||||||
|
The latest version of this library is available from GitHub:
|
||||||
|
https://github.com/libsdl-org/SDL_ttf/releases
|
||||||
|
|
||||||
|
Installation instructions and a quick introduction is available in
|
||||||
|
[INSTALL.md](INSTALL.md)
|
||||||
|
|
||||||
|
This library is distributed under the terms of the zlib license,
|
||||||
|
available in [LICENSE.txt](LICENSE.txt).
|
||||||
|
|
||||||
|
This library also uses the following libraries:
|
||||||
|
- FreeType, licensed under the [FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT)
|
||||||
|
- HarfBuzz, licensed under the [MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING)
|
||||||
|
- PlutoSVG, licensed under the [MIT license](https://github.com/sammycage/plutosvg/blob/master/LICENSE)
|
||||||
|
- PlutoVG, licensed under the [MIT license](https://github.com/sammycage/plutovg/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
Sam Lantinga (slouken@libsdl.org)
|
||||||
Binary file not shown.
@@ -0,0 +1,197 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>files</key>
|
||||||
|
<dict>
|
||||||
|
<key>Resources/CMake/SDL3_ttfConfig.cmake</key>
|
||||||
|
<data>
|
||||||
|
V6UpWQTvr/puOrlm1sgAs6fktNA=
|
||||||
|
</data>
|
||||||
|
<key>Resources/CMake/SDL3_ttfConfigVersion.cmake</key>
|
||||||
|
<data>
|
||||||
|
WW2xmNHZyYr9y3/8uAylJuutcPw=
|
||||||
|
</data>
|
||||||
|
<key>Resources/INSTALL.md</key>
|
||||||
|
<data>
|
||||||
|
3kA+9HE5dF7+nyypVt5YOfU+Uho=
|
||||||
|
</data>
|
||||||
|
<key>Resources/Info.plist</key>
|
||||||
|
<data>
|
||||||
|
Q+NCd9YwE/D/Y4ptVnrhOldXz6U=
|
||||||
|
</data>
|
||||||
|
<key>Resources/LICENSE.txt</key>
|
||||||
|
<data>
|
||||||
|
dp6e8JHkl0CrYD+oe2IXZfWB/iw=
|
||||||
|
</data>
|
||||||
|
<key>Resources/README.md</key>
|
||||||
|
<data>
|
||||||
|
lm034L4zWKPElKb9O2dmehurfFQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>files2</key>
|
||||||
|
<dict>
|
||||||
|
<key>Headers/SDL_textengine.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Uk27FTzsWoYySpKM1gkwCB/svSxscGViuMzca93gLP8=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/SDL_ttf.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
6bsCCUp3Uc3tCp+0Xxw7Tt01+UV8bra5YN1dFjpRBL0=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Resources/CMake/SDL3_ttfConfig.cmake</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
VpwUT/D8TjpLXBguVImWqsMkqni9HXiIzx91C92Krqc=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Resources/CMake/SDL3_ttfConfigVersion.cmake</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
tb1RnDTj72GQOzcXp6FPtiqW8tSD886UyUY09c1Ms/U=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Resources/INSTALL.md</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Jq9GEmdnFRmUTNnYYZZ+5mFqqrMelD86Gthhyi2kGJQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Resources/Info.plist</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
LwUSgLeBsUUT/M3w+W5AAfTziViNTWX1o7Ly+x3J2u0=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Resources/LICENSE.txt</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
eCbsoKD35ZHzjdhE4geiAKrIGlmyDYoww6+MYoKvE+Y=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Resources/README.md</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
6aipppbEU7MEd3x9OHnKqAGyFXVYiSAL8X8lm271U00=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>rules</key>
|
||||||
|
<dict>
|
||||||
|
<key>^Resources/</key>
|
||||||
|
<true/>
|
||||||
|
<key>^Resources/.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version.plist$</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>rules2</key>
|
||||||
|
<dict>
|
||||||
|
<key>.*\.dSYM($|/)</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>11</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(.*/)?\.DS_Store$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>2000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
||||||
|
<dict>
|
||||||
|
<key>nested</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>10</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^Info\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^PkgInfo$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Resources/Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^[^/]+$</key>
|
||||||
|
<dict>
|
||||||
|
<key>nested</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>10</real>
|
||||||
|
</dict>
|
||||||
|
<key>^embedded\.provisionprofile$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
A
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
|
||||||
|
Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file SDL_textengine.h
|
||||||
|
*
|
||||||
|
* Definitions for implementations of the TTF_TextEngine interface.
|
||||||
|
*/
|
||||||
|
#ifndef SDL_TTF_TEXTENGINE_H_
|
||||||
|
#define SDL_TTF_TEXTENGINE_H_
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A font atlas draw command.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef enum TTF_DrawCommand
|
||||||
|
{
|
||||||
|
TTF_DRAW_COMMAND_NOOP,
|
||||||
|
TTF_DRAW_COMMAND_FILL,
|
||||||
|
TTF_DRAW_COMMAND_COPY
|
||||||
|
} TTF_DrawCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filled rectangle draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_FillOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_FILL */
|
||||||
|
SDL_Rect rect; /**< The rectangle to fill, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
} TTF_FillOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A texture copy draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_CopyOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_COPY */
|
||||||
|
int text_offset; /**< The offset in the text corresponding to this glyph.
|
||||||
|
There may be multiple glyphs with the same text offset
|
||||||
|
and the next text offset might be several Unicode codepoints
|
||||||
|
later. In this case the glyphs and codepoints are grouped
|
||||||
|
together and the group bounding box is the union of the dst
|
||||||
|
rectangles for the corresponding glyphs. */
|
||||||
|
TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
SDL_Rect src; /**< The area within the glyph to be drawn */
|
||||||
|
SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
void *reserved;
|
||||||
|
} TTF_CopyOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef union TTF_DrawOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd;
|
||||||
|
TTF_FillOperation fill;
|
||||||
|
TTF_CopyOperation copy;
|
||||||
|
} TTF_DrawOperation;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, to assist in text measurement and layout */
|
||||||
|
typedef struct TTF_TextLayout TTF_TextLayout;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, available to implementations */
|
||||||
|
struct TTF_TextData
|
||||||
|
{
|
||||||
|
TTF_Font *font; /**< The font used by this text, read-only. */
|
||||||
|
SDL_FColor color; /**< The color of the text, read-only. */
|
||||||
|
|
||||||
|
bool needs_layout_update; /**< True if the layout needs to be updated */
|
||||||
|
TTF_TextLayout *layout; /**< Cached layout information, read-only. */
|
||||||
|
int x; /**< The x offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int y; /**< The y offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int w; /**< The width of this text, in pixels, read-only. */
|
||||||
|
int h; /**< The height of this text, in pixels, read-only. */
|
||||||
|
int num_ops; /**< The number of drawing operations to render this text, read-only. */
|
||||||
|
TTF_DrawOperation *ops; /**< The drawing operations used to render this text, read-only. */
|
||||||
|
int num_clusters; /**< The number of substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
TTF_SubString *clusters; /**< Substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
|
||||||
|
SDL_PropertiesID props; /**< Custom properties associated with this text, read-only. This field is created as-needed using TTF_GetTextProperties() and the properties may be then set and read normally */
|
||||||
|
|
||||||
|
bool needs_engine_update; /**< True if the engine text needs to be updated */
|
||||||
|
TTF_TextEngine *engine; /**< The engine used to render this text, read-only. */
|
||||||
|
void *engine_text; /**< The implementation-specific representation of this text */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine interface.
|
||||||
|
*
|
||||||
|
* This structure should be initialized using SDL_INIT_INTERFACE()
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_INIT_INTERFACE
|
||||||
|
*/
|
||||||
|
struct TTF_TextEngine
|
||||||
|
{
|
||||||
|
Uint32 version; /**< The version of this interface */
|
||||||
|
|
||||||
|
void *userdata; /**< User data pointer passed to callbacks */
|
||||||
|
|
||||||
|
/* Create a text representation from draw instructions.
|
||||||
|
*
|
||||||
|
* All fields of `text` except `internal->engine_text` will already be filled out.
|
||||||
|
*
|
||||||
|
* This function should set the `internal->engine_text` field to a non-NULL value.
|
||||||
|
*
|
||||||
|
* \param userdata the userdata pointer in this interface.
|
||||||
|
* \param text the text object being created.
|
||||||
|
*/
|
||||||
|
bool (SDLCALL *CreateText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a text representation.
|
||||||
|
*/
|
||||||
|
void (SDLCALL *DestroyText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Check the size of TTF_TextEngine
|
||||||
|
*
|
||||||
|
* If this assert fails, either the compiler is padding to an unexpected size,
|
||||||
|
* or the interface has been updated and this should be updated to match and
|
||||||
|
* the code using this interface should be updated to handle the old version.
|
||||||
|
*/
|
||||||
|
SDL_COMPILE_TIME_ASSERT(TTF_TextEngine_SIZE,
|
||||||
|
(sizeof(void *) == 4 && sizeof(TTF_TextEngine) == 16) ||
|
||||||
|
(sizeof(void *) == 8 && sizeof(TTF_TextEngine) == 32));
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_TTF_TEXTENGINE_H_ */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
# Using this package
|
||||||
|
|
||||||
|
This package contains SDL_ttf built for Xcode.
|
||||||
|
|
||||||
|
To use this package in Xcode, drag `SDL3_ttf.framework` into your project.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
An API reference and additional documentation is available at:
|
||||||
|
|
||||||
|
https://wiki.libsdl.org/SDL3_ttf
|
||||||
|
|
||||||
|
# Discussions
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
|
||||||
|
You can join the official Discord server at:
|
||||||
|
|
||||||
|
https://discord.com/invite/BwpFGBWsv8
|
||||||
|
|
||||||
|
## Forums/mailing lists
|
||||||
|
|
||||||
|
You can join SDL development discussions at:
|
||||||
|
|
||||||
|
https://discourse.libsdl.org/
|
||||||
|
|
||||||
|
Once you sign up, you can use the forum through the website or as a mailing list from your email client.
|
||||||
|
|
||||||
|
## Announcement list
|
||||||
|
|
||||||
|
You can sign up for the low traffic announcement list at:
|
||||||
|
|
||||||
|
https://www.libsdl.org/mailing-list.php
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
SDL_ttf 3.0
|
||||||
|
|
||||||
|
This library is a wrapper around the FreeType and Harfbuzz libraries, allowing you to use TrueType fonts to render text in SDL applications.
|
||||||
|
|
||||||
|
The latest version of this library is available from GitHub:
|
||||||
|
https://github.com/libsdl-org/SDL_ttf/releases
|
||||||
|
|
||||||
|
Installation instructions and a quick introduction is available in
|
||||||
|
[INSTALL.md](INSTALL.md)
|
||||||
|
|
||||||
|
This library is distributed under the terms of the zlib license,
|
||||||
|
available in [LICENSE.txt](LICENSE.txt).
|
||||||
|
|
||||||
|
This library also uses the following libraries:
|
||||||
|
- FreeType, licensed under the [FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT)
|
||||||
|
- HarfBuzz, licensed under the [MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING)
|
||||||
|
- PlutoSVG, licensed under the [MIT license](https://github.com/sammycage/plutosvg/blob/master/LICENSE)
|
||||||
|
- PlutoVG, licensed under the [MIT license](https://github.com/sammycage/plutovg/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
Sam Lantinga (slouken@libsdl.org)
|
||||||
BIN
release/frameworks/SDL3_ttf.xcframework/tvos-arm64/SDL3_ttf.framework/SDL3_ttf
Executable file
BIN
release/frameworks/SDL3_ttf.xcframework/tvos-arm64/SDL3_ttf.framework/SDL3_ttf
Executable file
Binary file not shown.
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
|
||||||
|
Copyright (C) 2001-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file SDL_textengine.h
|
||||||
|
*
|
||||||
|
* Definitions for implementations of the TTF_TextEngine interface.
|
||||||
|
*/
|
||||||
|
#ifndef SDL_TTF_TEXTENGINE_H_
|
||||||
|
#define SDL_TTF_TEXTENGINE_H_
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3_ttf/SDL_ttf.h>
|
||||||
|
|
||||||
|
#include <SDL3/SDL_begin_code.h>
|
||||||
|
|
||||||
|
/* Set up for C function definitions, even when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A font atlas draw command.
|
||||||
|
*
|
||||||
|
* \since This enum is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef enum TTF_DrawCommand
|
||||||
|
{
|
||||||
|
TTF_DRAW_COMMAND_NOOP,
|
||||||
|
TTF_DRAW_COMMAND_FILL,
|
||||||
|
TTF_DRAW_COMMAND_COPY
|
||||||
|
} TTF_DrawCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filled rectangle draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_FillOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_FILL */
|
||||||
|
SDL_Rect rect; /**< The rectangle to fill, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
} TTF_FillOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A texture copy draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa TTF_DrawOperation
|
||||||
|
*/
|
||||||
|
typedef struct TTF_CopyOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_COPY */
|
||||||
|
int text_offset; /**< The offset in the text corresponding to this glyph.
|
||||||
|
There may be multiple glyphs with the same text offset
|
||||||
|
and the next text offset might be several Unicode codepoints
|
||||||
|
later. In this case the glyphs and codepoints are grouped
|
||||||
|
together and the group bounding box is the union of the dst
|
||||||
|
rectangles for the corresponding glyphs. */
|
||||||
|
TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */
|
||||||
|
SDL_Rect src; /**< The area within the glyph to be drawn */
|
||||||
|
SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */
|
||||||
|
void *reserved;
|
||||||
|
} TTF_CopyOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine draw operation.
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*/
|
||||||
|
typedef union TTF_DrawOperation
|
||||||
|
{
|
||||||
|
TTF_DrawCommand cmd;
|
||||||
|
TTF_FillOperation fill;
|
||||||
|
TTF_CopyOperation copy;
|
||||||
|
} TTF_DrawOperation;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, to assist in text measurement and layout */
|
||||||
|
typedef struct TTF_TextLayout TTF_TextLayout;
|
||||||
|
|
||||||
|
|
||||||
|
/* Private data in TTF_Text, available to implementations */
|
||||||
|
struct TTF_TextData
|
||||||
|
{
|
||||||
|
TTF_Font *font; /**< The font used by this text, read-only. */
|
||||||
|
SDL_FColor color; /**< The color of the text, read-only. */
|
||||||
|
|
||||||
|
bool needs_layout_update; /**< True if the layout needs to be updated */
|
||||||
|
TTF_TextLayout *layout; /**< Cached layout information, read-only. */
|
||||||
|
int x; /**< The x offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int y; /**< The y offset of the upper left corner of this text, in pixels, read-only. */
|
||||||
|
int w; /**< The width of this text, in pixels, read-only. */
|
||||||
|
int h; /**< The height of this text, in pixels, read-only. */
|
||||||
|
int num_ops; /**< The number of drawing operations to render this text, read-only. */
|
||||||
|
TTF_DrawOperation *ops; /**< The drawing operations used to render this text, read-only. */
|
||||||
|
int num_clusters; /**< The number of substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
TTF_SubString *clusters; /**< Substrings representing clusters of glyphs in the string, read-only */
|
||||||
|
|
||||||
|
SDL_PropertiesID props; /**< Custom properties associated with this text, read-only. This field is created as-needed using TTF_GetTextProperties() and the properties may be then set and read normally */
|
||||||
|
|
||||||
|
bool needs_engine_update; /**< True if the engine text needs to be updated */
|
||||||
|
TTF_TextEngine *engine; /**< The engine used to render this text, read-only. */
|
||||||
|
void *engine_text; /**< The implementation-specific representation of this text */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text engine interface.
|
||||||
|
*
|
||||||
|
* This structure should be initialized using SDL_INIT_INTERFACE()
|
||||||
|
*
|
||||||
|
* \since This struct is available since SDL_ttf 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_INIT_INTERFACE
|
||||||
|
*/
|
||||||
|
struct TTF_TextEngine
|
||||||
|
{
|
||||||
|
Uint32 version; /**< The version of this interface */
|
||||||
|
|
||||||
|
void *userdata; /**< User data pointer passed to callbacks */
|
||||||
|
|
||||||
|
/* Create a text representation from draw instructions.
|
||||||
|
*
|
||||||
|
* All fields of `text` except `internal->engine_text` will already be filled out.
|
||||||
|
*
|
||||||
|
* This function should set the `internal->engine_text` field to a non-NULL value.
|
||||||
|
*
|
||||||
|
* \param userdata the userdata pointer in this interface.
|
||||||
|
* \param text the text object being created.
|
||||||
|
*/
|
||||||
|
bool (SDLCALL *CreateText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a text representation.
|
||||||
|
*/
|
||||||
|
void (SDLCALL *DestroyText)(void *userdata, TTF_Text *text);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Check the size of TTF_TextEngine
|
||||||
|
*
|
||||||
|
* If this assert fails, either the compiler is padding to an unexpected size,
|
||||||
|
* or the interface has been updated and this should be updated to match and
|
||||||
|
* the code using this interface should be updated to handle the old version.
|
||||||
|
*/
|
||||||
|
SDL_COMPILE_TIME_ASSERT(TTF_TextEngine_SIZE,
|
||||||
|
(sizeof(void *) == 4 && sizeof(TTF_TextEngine) == 16) ||
|
||||||
|
(sizeof(void *) == 8 && sizeof(TTF_TextEngine) == 32));
|
||||||
|
|
||||||
|
|
||||||
|
/* Ends C function definitions when using C++ */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#include <SDL3/SDL_close_code.h>
|
||||||
|
|
||||||
|
#endif /* SDL_TTF_TEXTENGINE_H_ */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
# Using this package
|
||||||
|
|
||||||
|
This package contains SDL_ttf built for Xcode.
|
||||||
|
|
||||||
|
To use this package in Xcode, drag `SDL3_ttf.framework` into your project.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
An API reference and additional documentation is available at:
|
||||||
|
|
||||||
|
https://wiki.libsdl.org/SDL3_ttf
|
||||||
|
|
||||||
|
# Discussions
|
||||||
|
|
||||||
|
## Discord
|
||||||
|
|
||||||
|
You can join the official Discord server at:
|
||||||
|
|
||||||
|
https://discord.com/invite/BwpFGBWsv8
|
||||||
|
|
||||||
|
## Forums/mailing lists
|
||||||
|
|
||||||
|
You can join SDL development discussions at:
|
||||||
|
|
||||||
|
https://discourse.libsdl.org/
|
||||||
|
|
||||||
|
Once you sign up, you can use the forum through the website or as a mailing list from your email client.
|
||||||
|
|
||||||
|
## Announcement list
|
||||||
|
|
||||||
|
You can sign up for the low traffic announcement list at:
|
||||||
|
|
||||||
|
https://www.libsdl.org/mailing-list.php
|
||||||
|
|
||||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
SDL_ttf 3.0
|
||||||
|
|
||||||
|
This library is a wrapper around the FreeType and Harfbuzz libraries, allowing you to use TrueType fonts to render text in SDL applications.
|
||||||
|
|
||||||
|
The latest version of this library is available from GitHub:
|
||||||
|
https://github.com/libsdl-org/SDL_ttf/releases
|
||||||
|
|
||||||
|
Installation instructions and a quick introduction is available in
|
||||||
|
[INSTALL.md](INSTALL.md)
|
||||||
|
|
||||||
|
This library is distributed under the terms of the zlib license,
|
||||||
|
available in [LICENSE.txt](LICENSE.txt).
|
||||||
|
|
||||||
|
This library also uses the following libraries:
|
||||||
|
- FreeType, licensed under the [FTL](https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/docs/FTL.TXT)
|
||||||
|
- HarfBuzz, licensed under the [MIT license](https://github.com/harfbuzz/harfbuzz/blob/main/COPYING)
|
||||||
|
- PlutoSVG, licensed under the [MIT license](https://github.com/sammycage/plutosvg/blob/master/LICENSE)
|
||||||
|
- PlutoVG, licensed under the [MIT license](https://github.com/sammycage/plutovg/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
|
||||||
|
Sam Lantinga (slouken@libsdl.org)
|
||||||
Binary file not shown.
@@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>files</key>
|
||||||
|
<dict>
|
||||||
|
<key>CMake/SDL3_ttfConfig.cmake</key>
|
||||||
|
<data>
|
||||||
|
V6UpWQTvr/puOrlm1sgAs6fktNA=
|
||||||
|
</data>
|
||||||
|
<key>CMake/SDL3_ttfConfigVersion.cmake</key>
|
||||||
|
<data>
|
||||||
|
WW2xmNHZyYr9y3/8uAylJuutcPw=
|
||||||
|
</data>
|
||||||
|
<key>Headers/SDL_textengine.h</key>
|
||||||
|
<data>
|
||||||
|
7QAtKpC/pLIq6TK3F59Ax1hg3tc=
|
||||||
|
</data>
|
||||||
|
<key>Headers/SDL_ttf.h</key>
|
||||||
|
<data>
|
||||||
|
90S4SFzJy1lUuMotaCRWpTbzRa4=
|
||||||
|
</data>
|
||||||
|
<key>INSTALL.md</key>
|
||||||
|
<data>
|
||||||
|
3kA+9HE5dF7+nyypVt5YOfU+Uho=
|
||||||
|
</data>
|
||||||
|
<key>Info.plist</key>
|
||||||
|
<data>
|
||||||
|
+nBymgIjvQrMA5f3CqiBB03/KB0=
|
||||||
|
</data>
|
||||||
|
<key>LICENSE.txt</key>
|
||||||
|
<data>
|
||||||
|
dp6e8JHkl0CrYD+oe2IXZfWB/iw=
|
||||||
|
</data>
|
||||||
|
<key>README.md</key>
|
||||||
|
<data>
|
||||||
|
lm034L4zWKPElKb9O2dmehurfFQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>files2</key>
|
||||||
|
<dict>
|
||||||
|
<key>CMake/SDL3_ttfConfig.cmake</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
VpwUT/D8TjpLXBguVImWqsMkqni9HXiIzx91C92Krqc=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>CMake/SDL3_ttfConfigVersion.cmake</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
tb1RnDTj72GQOzcXp6FPtiqW8tSD886UyUY09c1Ms/U=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/SDL_textengine.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Uk27FTzsWoYySpKM1gkwCB/svSxscGViuMzca93gLP8=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/SDL_ttf.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
6bsCCUp3Uc3tCp+0Xxw7Tt01+UV8bra5YN1dFjpRBL0=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>INSTALL.md</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Jq9GEmdnFRmUTNnYYZZ+5mFqqrMelD86Gthhyi2kGJQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>LICENSE.txt</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
eCbsoKD35ZHzjdhE4geiAKrIGlmyDYoww6+MYoKvE+Y=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>README.md</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
6aipppbEU7MEd3x9OHnKqAGyFXVYiSAL8X8lm271U00=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>rules</key>
|
||||||
|
<dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version.plist$</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>rules2</key>
|
||||||
|
<dict>
|
||||||
|
<key>.*\.dSYM($|/)</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>11</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(.*/)?\.DS_Store$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>2000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Info\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^PkgInfo$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^embedded\.provisionprofile$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
BIN
release/vibe3.res
Normal file
BIN
release/vibe3.res
Normal file
Binary file not shown.
BIN
resources.pack
BIN
resources.pack
Binary file not shown.
687
source/app_logo.cpp
Normal file
687
source/app_logo.cpp
Normal file
@@ -0,0 +1,687 @@
|
|||||||
|
#include "app_logo.hpp"
|
||||||
|
|
||||||
|
#include <SDL3/SDL_render.h> // for SDL_DestroyTexture, SDL_RenderGeometry, SDL_SetTextureAlphaMod
|
||||||
|
#include <cmath> // for powf, sinf, cosf
|
||||||
|
#include <cstdlib> // for free()
|
||||||
|
#include <iostream> // for std::cout
|
||||||
|
|
||||||
|
#include "logo_scaler.hpp" // for LogoScaler
|
||||||
|
#include "defines.hpp" // for APPLOGO_HEIGHT_PERCENT, getResourcesDirectory
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Destructor - Liberar las 4 texturas SDL
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
AppLogo::~AppLogo() {
|
||||||
|
if (logo1_base_texture_) {
|
||||||
|
SDL_DestroyTexture(logo1_base_texture_);
|
||||||
|
logo1_base_texture_ = nullptr;
|
||||||
|
}
|
||||||
|
if (logo1_native_texture_) {
|
||||||
|
SDL_DestroyTexture(logo1_native_texture_);
|
||||||
|
logo1_native_texture_ = nullptr;
|
||||||
|
}
|
||||||
|
if (logo2_base_texture_) {
|
||||||
|
SDL_DestroyTexture(logo2_base_texture_);
|
||||||
|
logo2_base_texture_ = nullptr;
|
||||||
|
}
|
||||||
|
if (logo2_native_texture_) {
|
||||||
|
SDL_DestroyTexture(logo2_native_texture_);
|
||||||
|
logo2_native_texture_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Inicialización - Pre-escalar logos a 2 resoluciones (base y nativa)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
bool AppLogo::initialize(SDL_Renderer* renderer, int screen_width, int screen_height) {
|
||||||
|
renderer_ = renderer;
|
||||||
|
base_screen_width_ = screen_width;
|
||||||
|
base_screen_height_ = screen_height;
|
||||||
|
screen_width_ = screen_width;
|
||||||
|
screen_height_ = screen_height;
|
||||||
|
|
||||||
|
std::string resources_dir = getResourcesDirectory();
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// 1. Detectar resolución nativa del monitor
|
||||||
|
// ========================================================================
|
||||||
|
if (!LogoScaler::detectNativeResolution(native_screen_width_, native_screen_height_)) {
|
||||||
|
std::cout << "No se pudo detectar resolución nativa, usando solo base" << std::endl;
|
||||||
|
// Fallback: usar resolución base como nativa
|
||||||
|
native_screen_width_ = screen_width;
|
||||||
|
native_screen_height_ = screen_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// 2. Calcular alturas finales para ambas resoluciones
|
||||||
|
// ========================================================================
|
||||||
|
int logo_base_target_height = static_cast<int>(base_screen_height_ * APPLOGO_HEIGHT_PERCENT);
|
||||||
|
int logo_native_target_height = static_cast<int>(native_screen_height_ * APPLOGO_HEIGHT_PERCENT);
|
||||||
|
|
||||||
|
std::cout << "Pre-escalando logos:" << std::endl;
|
||||||
|
std::cout << " Base: " << base_screen_width_ << "x" << base_screen_height_
|
||||||
|
<< " (altura logo: " << logo_base_target_height << "px)" << std::endl;
|
||||||
|
std::cout << " Nativa: " << native_screen_width_ << "x" << native_screen_height_
|
||||||
|
<< " (altura logo: " << logo_native_target_height << "px)" << std::endl;
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// 3. Cargar y escalar LOGO1 (data/logo/logo.png) a 2 versiones
|
||||||
|
// ========================================================================
|
||||||
|
std::string logo1_path = resources_dir + "/data/logo/logo.png";
|
||||||
|
|
||||||
|
// 3a. Versión BASE de logo1
|
||||||
|
unsigned char* logo1_base_data = LogoScaler::loadAndScale(
|
||||||
|
logo1_path,
|
||||||
|
0, // width calculado automáticamente por aspect ratio
|
||||||
|
logo_base_target_height,
|
||||||
|
logo1_base_width_,
|
||||||
|
logo1_base_height_
|
||||||
|
);
|
||||||
|
if (logo1_base_data == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo escalar logo1 (base)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo1_base_texture_ = LogoScaler::createTextureFromBuffer(
|
||||||
|
renderer, logo1_base_data, logo1_base_width_, logo1_base_height_
|
||||||
|
);
|
||||||
|
free(logo1_base_data); // Liberar buffer temporal
|
||||||
|
|
||||||
|
if (logo1_base_texture_ == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo crear textura logo1 (base)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Habilitar alpha blending
|
||||||
|
SDL_SetTextureBlendMode(logo1_base_texture_, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
// 3b. Versión NATIVA de logo1
|
||||||
|
unsigned char* logo1_native_data = LogoScaler::loadAndScale(
|
||||||
|
logo1_path,
|
||||||
|
0, // width calculado automáticamente
|
||||||
|
logo_native_target_height,
|
||||||
|
logo1_native_width_,
|
||||||
|
logo1_native_height_
|
||||||
|
);
|
||||||
|
if (logo1_native_data == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo escalar logo1 (nativa)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo1_native_texture_ = LogoScaler::createTextureFromBuffer(
|
||||||
|
renderer, logo1_native_data, logo1_native_width_, logo1_native_height_
|
||||||
|
);
|
||||||
|
free(logo1_native_data);
|
||||||
|
|
||||||
|
if (logo1_native_texture_ == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo crear textura logo1 (nativa)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetTextureBlendMode(logo1_native_texture_, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// 4. Cargar y escalar LOGO2 (data/logo/logo2.png) a 2 versiones
|
||||||
|
// ========================================================================
|
||||||
|
std::string logo2_path = resources_dir + "/data/logo/logo2.png";
|
||||||
|
|
||||||
|
// 4a. Versión BASE de logo2
|
||||||
|
unsigned char* logo2_base_data = LogoScaler::loadAndScale(
|
||||||
|
logo2_path,
|
||||||
|
0,
|
||||||
|
logo_base_target_height,
|
||||||
|
logo2_base_width_,
|
||||||
|
logo2_base_height_
|
||||||
|
);
|
||||||
|
if (logo2_base_data == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo escalar logo2 (base)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo2_base_texture_ = LogoScaler::createTextureFromBuffer(
|
||||||
|
renderer, logo2_base_data, logo2_base_width_, logo2_base_height_
|
||||||
|
);
|
||||||
|
free(logo2_base_data);
|
||||||
|
|
||||||
|
if (logo2_base_texture_ == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo crear textura logo2 (base)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetTextureBlendMode(logo2_base_texture_, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
// 4b. Versión NATIVA de logo2
|
||||||
|
unsigned char* logo2_native_data = LogoScaler::loadAndScale(
|
||||||
|
logo2_path,
|
||||||
|
0,
|
||||||
|
logo_native_target_height,
|
||||||
|
logo2_native_width_,
|
||||||
|
logo2_native_height_
|
||||||
|
);
|
||||||
|
if (logo2_native_data == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo escalar logo2 (nativa)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logo2_native_texture_ = LogoScaler::createTextureFromBuffer(
|
||||||
|
renderer, logo2_native_data, logo2_native_width_, logo2_native_height_
|
||||||
|
);
|
||||||
|
free(logo2_native_data);
|
||||||
|
|
||||||
|
if (logo2_native_texture_ == nullptr) {
|
||||||
|
std::cout << "Error: No se pudo crear textura logo2 (nativa)" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetTextureBlendMode(logo2_native_texture_, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// 5. Inicialmente usar texturas BASE (la resolución de inicio)
|
||||||
|
// ========================================================================
|
||||||
|
logo1_current_texture_ = logo1_base_texture_;
|
||||||
|
logo1_current_width_ = logo1_base_width_;
|
||||||
|
logo1_current_height_ = logo1_base_height_;
|
||||||
|
|
||||||
|
logo2_current_texture_ = logo2_base_texture_;
|
||||||
|
logo2_current_width_ = logo2_base_width_;
|
||||||
|
logo2_current_height_ = logo2_base_height_;
|
||||||
|
|
||||||
|
std::cout << "Logos pre-escalados exitosamente (4 texturas creadas)" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppLogo::update(float delta_time, AppMode current_mode) {
|
||||||
|
// Si estamos en SANDBOX, resetear y no hacer nada (logo desactivado)
|
||||||
|
if (current_mode == AppMode::SANDBOX) {
|
||||||
|
state_ = AppLogoState::HIDDEN;
|
||||||
|
timer_ = 0.0f;
|
||||||
|
logo1_alpha_ = 0;
|
||||||
|
logo2_alpha_ = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Máquina de estados con fade in/out
|
||||||
|
timer_ += delta_time;
|
||||||
|
|
||||||
|
switch (state_) {
|
||||||
|
case AppLogoState::HIDDEN:
|
||||||
|
// Esperando el intervalo de espera
|
||||||
|
if (timer_ >= APPLOGO_DISPLAY_INTERVAL) {
|
||||||
|
state_ = AppLogoState::FADE_IN;
|
||||||
|
timer_ = 0.0f;
|
||||||
|
logo1_alpha_ = 0;
|
||||||
|
logo2_alpha_ = 0;
|
||||||
|
// Elegir UNA animación aleatoria (misma para ambos logos, misma entrada y salida)
|
||||||
|
current_animation_ = getRandomAnimation();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoState::FADE_IN:
|
||||||
|
// Fade in: alpha de 0 a 255, con Logo 2 retrasado 0.25s
|
||||||
|
{
|
||||||
|
// Calcular progreso de cada logo (Logo 2 con retraso)
|
||||||
|
float fade_progress_logo1 = timer_ / APPLOGO_ANIMATION_DURATION;
|
||||||
|
float fade_progress_logo2 = std::max(0.0f, (timer_ - APPLOGO_LOGO2_DELAY) / APPLOGO_ANIMATION_DURATION);
|
||||||
|
|
||||||
|
// Verificar si fade in completado (cuando logo2 también termina)
|
||||||
|
if (fade_progress_logo2 >= 1.0f) {
|
||||||
|
// Fade in completado para ambos logos
|
||||||
|
state_ = AppLogoState::VISIBLE;
|
||||||
|
timer_ = 0.0f;
|
||||||
|
logo1_alpha_ = 255;
|
||||||
|
logo2_alpha_ = 255;
|
||||||
|
// Resetear variables de ambos logos
|
||||||
|
logo1_scale_ = 1.0f;
|
||||||
|
logo1_squash_y_ = 1.0f;
|
||||||
|
logo1_stretch_x_ = 1.0f;
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
logo2_scale_ = 1.0f;
|
||||||
|
logo2_squash_y_ = 1.0f;
|
||||||
|
logo2_stretch_x_ = 1.0f;
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
} else {
|
||||||
|
// Interpolar alpha con retraso de forma LINEAL (sin easing)
|
||||||
|
logo1_alpha_ = static_cast<int>(std::min(1.0f, fade_progress_logo1) * 255.0f);
|
||||||
|
logo2_alpha_ = static_cast<int>(std::min(1.0f, fade_progress_logo2) * 255.0f);
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// Aplicar MISMA animación (current_animation_) a ambos logos
|
||||||
|
// con sus respectivos progresos
|
||||||
|
// ================================================================
|
||||||
|
switch (current_animation_) {
|
||||||
|
case AppLogoAnimationType::ZOOM_ONLY:
|
||||||
|
logo1_scale_ = 1.2f - (std::min(1.0f, fade_progress_logo1) * 0.2f);
|
||||||
|
logo1_squash_y_ = 1.0f;
|
||||||
|
logo1_stretch_x_ = 1.0f;
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
|
||||||
|
logo2_scale_ = 1.2f - (std::min(1.0f, fade_progress_logo2) * 0.2f);
|
||||||
|
logo2_squash_y_ = 1.0f;
|
||||||
|
logo2_stretch_x_ = 1.0f;
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoAnimationType::ELASTIC_STICK:
|
||||||
|
{
|
||||||
|
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||||
|
float elastic_t1 = easeOutElastic(prog1);
|
||||||
|
logo1_scale_ = 1.2f - (elastic_t1 * 0.2f);
|
||||||
|
float squash_t1 = easeOutBack(prog1);
|
||||||
|
logo1_squash_y_ = 0.6f + (squash_t1 * 0.4f);
|
||||||
|
logo1_stretch_x_ = 1.0f + (1.0f - logo1_squash_y_) * 0.5f;
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
|
||||||
|
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||||
|
float elastic_t2 = easeOutElastic(prog2);
|
||||||
|
logo2_scale_ = 1.2f - (elastic_t2 * 0.2f);
|
||||||
|
float squash_t2 = easeOutBack(prog2);
|
||||||
|
logo2_squash_y_ = 0.6f + (squash_t2 * 0.4f);
|
||||||
|
logo2_stretch_x_ = 1.0f + (1.0f - logo2_squash_y_) * 0.5f;
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoAnimationType::ROTATE_SPIRAL:
|
||||||
|
{
|
||||||
|
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||||
|
float ease_t1 = easeInOutQuad(prog1);
|
||||||
|
logo1_scale_ = 0.3f + (ease_t1 * 0.7f);
|
||||||
|
logo1_rotation_ = (1.0f - prog1) * 6.28f;
|
||||||
|
logo1_squash_y_ = 1.0f;
|
||||||
|
logo1_stretch_x_ = 1.0f;
|
||||||
|
|
||||||
|
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||||
|
float ease_t2 = easeInOutQuad(prog2);
|
||||||
|
logo2_scale_ = 0.3f + (ease_t2 * 0.7f);
|
||||||
|
logo2_rotation_ = (1.0f - prog2) * 6.28f;
|
||||||
|
logo2_squash_y_ = 1.0f;
|
||||||
|
logo2_stretch_x_ = 1.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoAnimationType::BOUNCE_SQUASH:
|
||||||
|
{
|
||||||
|
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||||
|
float bounce_t1 = easeOutBounce(prog1);
|
||||||
|
logo1_scale_ = 1.0f;
|
||||||
|
float squash_amount1 = (1.0f - bounce_t1) * 0.3f;
|
||||||
|
logo1_squash_y_ = 1.0f - squash_amount1;
|
||||||
|
logo1_stretch_x_ = 1.0f + squash_amount1 * 0.5f;
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
|
||||||
|
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||||
|
float bounce_t2 = easeOutBounce(prog2);
|
||||||
|
logo2_scale_ = 1.0f;
|
||||||
|
float squash_amount2 = (1.0f - bounce_t2) * 0.3f;
|
||||||
|
logo2_squash_y_ = 1.0f - squash_amount2;
|
||||||
|
logo2_stretch_x_ = 1.0f + squash_amount2 * 0.5f;
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoState::VISIBLE:
|
||||||
|
// Logo completamente visible, esperando duración
|
||||||
|
if (timer_ >= APPLOGO_DISPLAY_DURATION) {
|
||||||
|
state_ = AppLogoState::FADE_OUT;
|
||||||
|
timer_ = 0.0f;
|
||||||
|
logo1_alpha_ = 255;
|
||||||
|
logo2_alpha_ = 255;
|
||||||
|
// NO elegir nueva animación - reutilizar current_animation_ (simetría entrada/salida)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoState::FADE_OUT:
|
||||||
|
// Fade out: alpha de 255 a 0, con Logo 2 retrasado 0.25s (misma animación que entrada)
|
||||||
|
{
|
||||||
|
// Calcular progreso de cada logo (Logo 2 con retraso)
|
||||||
|
float fade_progress_logo1 = timer_ / APPLOGO_ANIMATION_DURATION;
|
||||||
|
float fade_progress_logo2 = std::max(0.0f, (timer_ - APPLOGO_LOGO2_DELAY) / APPLOGO_ANIMATION_DURATION);
|
||||||
|
|
||||||
|
// Verificar si fade out completado (cuando logo2 también termina)
|
||||||
|
if (fade_progress_logo2 >= 1.0f) {
|
||||||
|
// Fade out completado, volver a HIDDEN
|
||||||
|
state_ = AppLogoState::HIDDEN;
|
||||||
|
timer_ = 0.0f;
|
||||||
|
logo1_alpha_ = 0;
|
||||||
|
logo2_alpha_ = 0;
|
||||||
|
// Resetear variables de ambos logos
|
||||||
|
logo1_scale_ = 1.0f;
|
||||||
|
logo1_squash_y_ = 1.0f;
|
||||||
|
logo1_stretch_x_ = 1.0f;
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
logo2_scale_ = 1.0f;
|
||||||
|
logo2_squash_y_ = 1.0f;
|
||||||
|
logo2_stretch_x_ = 1.0f;
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
} else {
|
||||||
|
// Interpolar alpha con retraso de forma LINEAL (255 → 0, sin easing)
|
||||||
|
logo1_alpha_ = static_cast<int>((1.0f - std::min(1.0f, fade_progress_logo1)) * 255.0f);
|
||||||
|
logo2_alpha_ = static_cast<int>((1.0f - std::min(1.0f, fade_progress_logo2)) * 255.0f);
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// Aplicar MISMA animación (current_animation_) de forma invertida
|
||||||
|
// ================================================================
|
||||||
|
switch (current_animation_) {
|
||||||
|
case AppLogoAnimationType::ZOOM_ONLY:
|
||||||
|
logo1_scale_ = 1.0f + (std::min(1.0f, fade_progress_logo1) * 0.2f);
|
||||||
|
logo1_squash_y_ = 1.0f;
|
||||||
|
logo1_stretch_x_ = 1.0f;
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
|
||||||
|
logo2_scale_ = 1.0f + (std::min(1.0f, fade_progress_logo2) * 0.2f);
|
||||||
|
logo2_squash_y_ = 1.0f;
|
||||||
|
logo2_stretch_x_ = 1.0f;
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoAnimationType::ELASTIC_STICK:
|
||||||
|
{
|
||||||
|
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||||
|
logo1_scale_ = 1.0f + (prog1 * prog1 * 0.2f);
|
||||||
|
logo1_squash_y_ = 1.0f + (prog1 * 0.3f);
|
||||||
|
logo1_stretch_x_ = 1.0f - (prog1 * 0.2f);
|
||||||
|
logo1_rotation_ = prog1 * 0.1f;
|
||||||
|
|
||||||
|
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||||
|
logo2_scale_ = 1.0f + (prog2 * prog2 * 0.2f);
|
||||||
|
logo2_squash_y_ = 1.0f + (prog2 * 0.3f);
|
||||||
|
logo2_stretch_x_ = 1.0f - (prog2 * 0.2f);
|
||||||
|
logo2_rotation_ = prog2 * 0.1f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoAnimationType::ROTATE_SPIRAL:
|
||||||
|
{
|
||||||
|
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||||
|
float ease_t1 = easeInOutQuad(prog1);
|
||||||
|
logo1_scale_ = 1.0f - (ease_t1 * 0.7f);
|
||||||
|
logo1_rotation_ = prog1 * 6.28f;
|
||||||
|
logo1_squash_y_ = 1.0f;
|
||||||
|
logo1_stretch_x_ = 1.0f;
|
||||||
|
|
||||||
|
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||||
|
float ease_t2 = easeInOutQuad(prog2);
|
||||||
|
logo2_scale_ = 1.0f - (ease_t2 * 0.7f);
|
||||||
|
logo2_rotation_ = prog2 * 6.28f;
|
||||||
|
logo2_squash_y_ = 1.0f;
|
||||||
|
logo2_stretch_x_ = 1.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AppLogoAnimationType::BOUNCE_SQUASH:
|
||||||
|
{
|
||||||
|
float prog1 = std::min(1.0f, fade_progress_logo1);
|
||||||
|
if (prog1 < 0.2f) {
|
||||||
|
float squash_t = prog1 / 0.2f;
|
||||||
|
logo1_squash_y_ = 1.0f - (squash_t * 0.3f);
|
||||||
|
logo1_stretch_x_ = 1.0f + (squash_t * 0.2f);
|
||||||
|
} else {
|
||||||
|
float jump_t = (prog1 - 0.2f) / 0.8f;
|
||||||
|
logo1_squash_y_ = 0.7f + (jump_t * 0.5f);
|
||||||
|
logo1_stretch_x_ = 1.2f - (jump_t * 0.2f);
|
||||||
|
}
|
||||||
|
logo1_scale_ = 1.0f + (prog1 * 0.3f);
|
||||||
|
logo1_rotation_ = 0.0f;
|
||||||
|
|
||||||
|
float prog2 = std::min(1.0f, fade_progress_logo2);
|
||||||
|
if (prog2 < 0.2f) {
|
||||||
|
float squash_t = prog2 / 0.2f;
|
||||||
|
logo2_squash_y_ = 1.0f - (squash_t * 0.3f);
|
||||||
|
logo2_stretch_x_ = 1.0f + (squash_t * 0.2f);
|
||||||
|
} else {
|
||||||
|
float jump_t = (prog2 - 0.2f) / 0.8f;
|
||||||
|
logo2_squash_y_ = 0.7f + (jump_t * 0.5f);
|
||||||
|
logo2_stretch_x_ = 1.2f - (jump_t * 0.2f);
|
||||||
|
}
|
||||||
|
logo2_scale_ = 1.0f + (prog2 * 0.3f);
|
||||||
|
logo2_rotation_ = 0.0f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppLogo::render() {
|
||||||
|
// Renderizar si NO está en estado HIDDEN (incluye FADE_IN, VISIBLE, FADE_OUT)
|
||||||
|
if (state_ != AppLogoState::HIDDEN) {
|
||||||
|
// Renderizar LOGO1 primero (fondo), luego LOGO2 (encima)
|
||||||
|
renderWithGeometry(1);
|
||||||
|
renderWithGeometry(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppLogo::updateScreenSize(int screen_width, int screen_height) {
|
||||||
|
screen_width_ = screen_width;
|
||||||
|
screen_height_ = screen_height;
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Detectar si coincide con resolución nativa o base, cambiar texturas
|
||||||
|
// ========================================================================
|
||||||
|
bool is_native = (screen_width == native_screen_width_ && screen_height == native_screen_height_);
|
||||||
|
|
||||||
|
if (is_native) {
|
||||||
|
// Cambiar a texturas nativas (F4 fullscreen)
|
||||||
|
logo1_current_texture_ = logo1_native_texture_;
|
||||||
|
logo1_current_width_ = logo1_native_width_;
|
||||||
|
logo1_current_height_ = logo1_native_height_;
|
||||||
|
|
||||||
|
logo2_current_texture_ = logo2_native_texture_;
|
||||||
|
logo2_current_width_ = logo2_native_width_;
|
||||||
|
logo2_current_height_ = logo2_native_height_;
|
||||||
|
|
||||||
|
std::cout << "AppLogo: Cambiado a texturas NATIVAS" << std::endl;
|
||||||
|
} else {
|
||||||
|
// Cambiar a texturas base (ventana redimensionable)
|
||||||
|
logo1_current_texture_ = logo1_base_texture_;
|
||||||
|
logo1_current_width_ = logo1_base_width_;
|
||||||
|
logo1_current_height_ = logo1_base_height_;
|
||||||
|
|
||||||
|
logo2_current_texture_ = logo2_base_texture_;
|
||||||
|
logo2_current_width_ = logo2_base_width_;
|
||||||
|
logo2_current_height_ = logo2_base_height_;
|
||||||
|
|
||||||
|
std::cout << "AppLogo: Cambiado a texturas BASE" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nota: No es necesario recalcular escalas porque las texturas están pre-escaladas
|
||||||
|
// al tamaño exacto de pantalla. Solo renderizamos al 100% (o con deformaciones de animación).
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Funciones de easing para animaciones
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
float AppLogo::easeOutElastic(float t) {
|
||||||
|
// Elastic easing out: bounce elástico al final
|
||||||
|
const float c4 = (2.0f * 3.14159f) / 3.0f;
|
||||||
|
|
||||||
|
if (t == 0.0f) return 0.0f;
|
||||||
|
if (t == 1.0f) return 1.0f;
|
||||||
|
|
||||||
|
return powf(2.0f, -10.0f * t) * sinf((t * 10.0f - 0.75f) * c4) + 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AppLogo::easeOutBack(float t) {
|
||||||
|
// Back easing out: overshoot suave al final
|
||||||
|
const float c1 = 1.70158f;
|
||||||
|
const float c3 = c1 + 1.0f;
|
||||||
|
|
||||||
|
return 1.0f + c3 * powf(t - 1.0f, 3.0f) + c1 * powf(t - 1.0f, 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float AppLogo::easeOutBounce(float t) {
|
||||||
|
// Bounce easing out: rebotes decrecientes (para BOUNCE_SQUASH)
|
||||||
|
const float n1 = 7.5625f;
|
||||||
|
const float d1 = 2.75f;
|
||||||
|
|
||||||
|
if (t < 1.0f / d1) {
|
||||||
|
return n1 * t * t;
|
||||||
|
} else if (t < 2.0f / d1) {
|
||||||
|
t -= 1.5f / d1;
|
||||||
|
return n1 * t * t + 0.75f;
|
||||||
|
} else if (t < 2.5f / d1) {
|
||||||
|
t -= 2.25f / d1;
|
||||||
|
return n1 * t * t + 0.9375f;
|
||||||
|
} else {
|
||||||
|
t -= 2.625f / d1;
|
||||||
|
return n1 * t * t + 0.984375f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float AppLogo::easeInOutQuad(float t) {
|
||||||
|
// Quadratic easing in/out: aceleración suave (para ROTATE_SPIRAL)
|
||||||
|
if (t < 0.5f) {
|
||||||
|
return 2.0f * t * t;
|
||||||
|
} else {
|
||||||
|
return 1.0f - powf(-2.0f * t + 2.0f, 2.0f) / 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Función auxiliar para aleatorización
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
AppLogoAnimationType AppLogo::getRandomAnimation() {
|
||||||
|
// Generar número aleatorio entre 0 y 3 (4 tipos de animación)
|
||||||
|
int random_value = rand() % 4;
|
||||||
|
|
||||||
|
switch (random_value) {
|
||||||
|
case 0:
|
||||||
|
return AppLogoAnimationType::ZOOM_ONLY;
|
||||||
|
case 1:
|
||||||
|
return AppLogoAnimationType::ELASTIC_STICK;
|
||||||
|
case 2:
|
||||||
|
return AppLogoAnimationType::ROTATE_SPIRAL;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
return AppLogoAnimationType::BOUNCE_SQUASH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Renderizado con geometría (para todos los logos, con deformaciones)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void AppLogo::renderWithGeometry(int logo_index) {
|
||||||
|
if (!renderer_) return;
|
||||||
|
|
||||||
|
// Seleccionar variables según el logo_index (1 = logo1, 2 = logo2)
|
||||||
|
SDL_Texture* texture;
|
||||||
|
int base_width, base_height;
|
||||||
|
float scale, squash_y, stretch_x, rotation;
|
||||||
|
|
||||||
|
if (logo_index == 1) {
|
||||||
|
if (!logo1_current_texture_) return;
|
||||||
|
texture = logo1_current_texture_;
|
||||||
|
base_width = logo1_current_width_;
|
||||||
|
base_height = logo1_current_height_;
|
||||||
|
scale = logo1_scale_;
|
||||||
|
squash_y = logo1_squash_y_;
|
||||||
|
stretch_x = logo1_stretch_x_;
|
||||||
|
rotation = logo1_rotation_;
|
||||||
|
} else if (logo_index == 2) {
|
||||||
|
if (!logo2_current_texture_) return;
|
||||||
|
texture = logo2_current_texture_;
|
||||||
|
base_width = logo2_current_width_;
|
||||||
|
base_height = logo2_current_height_;
|
||||||
|
scale = logo2_scale_;
|
||||||
|
squash_y = logo2_squash_y_;
|
||||||
|
stretch_x = logo2_stretch_x_;
|
||||||
|
rotation = logo2_rotation_;
|
||||||
|
} else {
|
||||||
|
return; // Índice inválido
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aplicar alpha específico de cada logo (con retraso para logo2)
|
||||||
|
int alpha = (logo_index == 1) ? logo1_alpha_ : logo2_alpha_;
|
||||||
|
float alpha_normalized = static_cast<float>(alpha) / 255.0f; // Convertir 0-255 → 0.0-1.0
|
||||||
|
// NO usar SDL_SetTextureAlphaMod - aplicar alpha directamente a vértices
|
||||||
|
|
||||||
|
// Calcular padding desde bordes derecho e inferior
|
||||||
|
float padding_x = screen_width_ * APPLOGO_PADDING_PERCENT;
|
||||||
|
float padding_y = screen_height_ * APPLOGO_PADDING_PERCENT;
|
||||||
|
|
||||||
|
// Calcular esquina BASE (sin escala) para obtener centro FIJO
|
||||||
|
// Esto asegura que el centro no se mueva cuando cambia scale/squash/stretch
|
||||||
|
float corner_x_base = screen_width_ - base_width - padding_x;
|
||||||
|
float corner_y_base = screen_height_ - base_height - padding_y;
|
||||||
|
|
||||||
|
// Centro FIJO del logo (no cambia con scale/squash/stretch)
|
||||||
|
float center_x = corner_x_base + (base_width / 2.0f);
|
||||||
|
float center_y = corner_y_base + (base_height / 2.0f);
|
||||||
|
|
||||||
|
// Calcular tamaño ESCALADO (para vértices)
|
||||||
|
// (base_width y base_height ya están pre-escalados al tamaño correcto de pantalla)
|
||||||
|
float width = base_width * scale * stretch_x;
|
||||||
|
float height = base_height * scale * squash_y;
|
||||||
|
|
||||||
|
// Pre-calcular seno y coseno de rotación
|
||||||
|
float cos_rot = cosf(rotation);
|
||||||
|
float sin_rot = sinf(rotation);
|
||||||
|
|
||||||
|
// Crear 4 vértices del quad (centrado en center_x, center_y)
|
||||||
|
SDL_Vertex vertices[4];
|
||||||
|
|
||||||
|
// Offset desde el centro
|
||||||
|
float half_w = width / 2.0f;
|
||||||
|
float half_h = height / 2.0f;
|
||||||
|
|
||||||
|
// Vértice superior izquierdo (rotado)
|
||||||
|
{
|
||||||
|
float local_x = -half_w;
|
||||||
|
float local_y = -half_h;
|
||||||
|
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||||
|
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||||
|
vertices[0].position = {center_x + rotated_x, center_y + rotated_y};
|
||||||
|
vertices[0].tex_coord = {0.0f, 0.0f};
|
||||||
|
vertices[0].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vértice superior derecho (rotado)
|
||||||
|
{
|
||||||
|
float local_x = half_w;
|
||||||
|
float local_y = -half_h;
|
||||||
|
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||||
|
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||||
|
vertices[1].position = {center_x + rotated_x, center_y + rotated_y};
|
||||||
|
vertices[1].tex_coord = {1.0f, 0.0f};
|
||||||
|
vertices[1].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vértice inferior derecho (rotado)
|
||||||
|
{
|
||||||
|
float local_x = half_w;
|
||||||
|
float local_y = half_h;
|
||||||
|
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||||
|
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||||
|
vertices[2].position = {center_x + rotated_x, center_y + rotated_y};
|
||||||
|
vertices[2].tex_coord = {1.0f, 1.0f};
|
||||||
|
vertices[2].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vértice inferior izquierdo (rotado)
|
||||||
|
{
|
||||||
|
float local_x = -half_w;
|
||||||
|
float local_y = half_h;
|
||||||
|
float rotated_x = local_x * cos_rot - local_y * sin_rot;
|
||||||
|
float rotated_y = local_x * sin_rot + local_y * cos_rot;
|
||||||
|
vertices[3].position = {center_x + rotated_x, center_y + rotated_y};
|
||||||
|
vertices[3].tex_coord = {0.0f, 1.0f};
|
||||||
|
vertices[3].color = {1.0f, 1.0f, 1.0f, alpha_normalized}; // Alpha aplicado al vértice
|
||||||
|
}
|
||||||
|
|
||||||
|
// Índices para 2 triángulos
|
||||||
|
int indices[6] = {0, 1, 2, 2, 3, 0};
|
||||||
|
|
||||||
|
// Renderizar con la textura del logo correspondiente
|
||||||
|
SDL_RenderGeometry(renderer_, texture, vertices, 4, indices, 6);
|
||||||
|
}
|
||||||
117
source/app_logo.hpp
Normal file
117
source/app_logo.hpp
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL_render.h> // for SDL_Renderer
|
||||||
|
|
||||||
|
#include <memory> // for unique_ptr, shared_ptr
|
||||||
|
|
||||||
|
#include "defines.hpp" // for AppMode
|
||||||
|
|
||||||
|
class Texture;
|
||||||
|
class Sprite;
|
||||||
|
|
||||||
|
// Estados de la máquina de estados del logo
|
||||||
|
enum class AppLogoState {
|
||||||
|
HIDDEN, // Logo oculto, esperando APPLOGO_DISPLAY_INTERVAL
|
||||||
|
FADE_IN, // Apareciendo (alpha 0 → 255)
|
||||||
|
VISIBLE, // Completamente visible, esperando APPLOGO_DISPLAY_DURATION
|
||||||
|
FADE_OUT // Desapareciendo (alpha 255 → 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tipo de animación de entrada/salida
|
||||||
|
enum class AppLogoAnimationType {
|
||||||
|
ZOOM_ONLY, // A: Solo zoom simple (120% → 100% → 120%)
|
||||||
|
ELASTIC_STICK, // B: Zoom + deformación elástica tipo "pegatina"
|
||||||
|
ROTATE_SPIRAL, // C: Rotación en espiral (entra girando, sale girando)
|
||||||
|
BOUNCE_SQUASH // D: Rebote con aplastamiento (cae rebotando, salta)
|
||||||
|
};
|
||||||
|
|
||||||
|
class AppLogo {
|
||||||
|
public:
|
||||||
|
AppLogo() = default;
|
||||||
|
~AppLogo(); // Necesario para liberar las 4 texturas SDL
|
||||||
|
|
||||||
|
// Inicializar textura y sprite del logo
|
||||||
|
bool initialize(SDL_Renderer* renderer, int screen_width, int screen_height);
|
||||||
|
|
||||||
|
// Actualizar temporizadores y estado de visibilidad
|
||||||
|
void update(float delta_time, AppMode current_mode);
|
||||||
|
|
||||||
|
// Renderizar logo si está visible
|
||||||
|
void render();
|
||||||
|
|
||||||
|
// Actualizar tamaño de pantalla (reposicionar logo)
|
||||||
|
void updateScreenSize(int screen_width, int screen_height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// ====================================================================
|
||||||
|
// Texturas pre-escaladas (4 texturas: 2 logos × 2 resoluciones)
|
||||||
|
// ====================================================================
|
||||||
|
SDL_Texture* logo1_base_texture_ = nullptr; // Logo1 para resolución base
|
||||||
|
SDL_Texture* logo1_native_texture_ = nullptr; // Logo1 para resolución nativa (F4)
|
||||||
|
SDL_Texture* logo2_base_texture_ = nullptr; // Logo2 para resolución base
|
||||||
|
SDL_Texture* logo2_native_texture_ = nullptr; // Logo2 para resolución nativa (F4)
|
||||||
|
|
||||||
|
// Dimensiones pre-calculadas para cada textura
|
||||||
|
int logo1_base_width_ = 0, logo1_base_height_ = 0;
|
||||||
|
int logo1_native_width_ = 0, logo1_native_height_ = 0;
|
||||||
|
int logo2_base_width_ = 0, logo2_base_height_ = 0;
|
||||||
|
int logo2_native_width_ = 0, logo2_native_height_ = 0;
|
||||||
|
|
||||||
|
// Texturas actualmente en uso (apuntan a base o native según resolución)
|
||||||
|
SDL_Texture* logo1_current_texture_ = nullptr;
|
||||||
|
SDL_Texture* logo2_current_texture_ = nullptr;
|
||||||
|
int logo1_current_width_ = 0, logo1_current_height_ = 0;
|
||||||
|
int logo2_current_width_ = 0, logo2_current_height_ = 0;
|
||||||
|
|
||||||
|
// Resoluciones conocidas
|
||||||
|
int base_screen_width_ = 0, base_screen_height_ = 0; // Resolución inicial
|
||||||
|
int native_screen_width_ = 0, native_screen_height_ = 0; // Resolución nativa (F4)
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// Variables COMPARTIDAS (sincronización de ambos logos)
|
||||||
|
// ====================================================================
|
||||||
|
AppLogoState state_ = AppLogoState::HIDDEN; // Estado actual de la máquina de estados
|
||||||
|
float timer_ = 0.0f; // Contador de tiempo para estado actual
|
||||||
|
|
||||||
|
// Alpha INDEPENDIENTE para cada logo (Logo 2 con retraso)
|
||||||
|
int logo1_alpha_ = 0; // Alpha de Logo 1 (0-255)
|
||||||
|
int logo2_alpha_ = 0; // Alpha de Logo 2 (0-255, con retraso)
|
||||||
|
|
||||||
|
// Animación COMPARTIDA (misma para ambos logos, misma entrada y salida)
|
||||||
|
AppLogoAnimationType current_animation_ = AppLogoAnimationType::ZOOM_ONLY;
|
||||||
|
|
||||||
|
// Variables de deformación INDEPENDIENTES para logo1
|
||||||
|
float logo1_scale_ = 1.0f; // Escala actual de logo1 (1.0 = 100%)
|
||||||
|
float logo1_squash_y_ = 1.0f; // Factor de aplastamiento vertical logo1
|
||||||
|
float logo1_stretch_x_ = 1.0f; // Factor de estiramiento horizontal logo1
|
||||||
|
float logo1_rotation_ = 0.0f; // Rotación en radianes logo1
|
||||||
|
|
||||||
|
// Variables de deformación INDEPENDIENTES para logo2
|
||||||
|
float logo2_scale_ = 1.0f; // Escala actual de logo2 (1.0 = 100%)
|
||||||
|
float logo2_squash_y_ = 1.0f; // Factor de aplastamiento vertical logo2
|
||||||
|
float logo2_stretch_x_ = 1.0f; // Factor de estiramiento horizontal logo2
|
||||||
|
float logo2_rotation_ = 0.0f; // Rotación en radianes logo2
|
||||||
|
|
||||||
|
int screen_width_ = 0; // Ancho de pantalla (para centrar)
|
||||||
|
int screen_height_ = 0; // Alto de pantalla (para centrar)
|
||||||
|
|
||||||
|
// Tamaño base del logo (calculado una vez)
|
||||||
|
float base_width_ = 0.0f;
|
||||||
|
float base_height_ = 0.0f;
|
||||||
|
|
||||||
|
// SDL renderer (necesario para renderizado con geometría)
|
||||||
|
SDL_Renderer* renderer_ = nullptr;
|
||||||
|
|
||||||
|
// Métodos privados auxiliares
|
||||||
|
void updateLogoPosition(); // Centrar ambos logos en pantalla (superpuestos)
|
||||||
|
void renderWithGeometry(int logo_index); // Renderizar logo con vértices deformados (1 o 2)
|
||||||
|
|
||||||
|
// Funciones de easing
|
||||||
|
float easeOutElastic(float t); // Elastic bounce out
|
||||||
|
float easeOutBack(float t); // Overshoot out
|
||||||
|
float easeOutBounce(float t); // Bounce easing (para BOUNCE_SQUASH)
|
||||||
|
float easeInOutQuad(float t); // Quadratic easing (para ROTATE_SPIRAL)
|
||||||
|
|
||||||
|
// Función auxiliar para elegir animación aleatoria
|
||||||
|
AppLogoAnimationType getRandomAnimation();
|
||||||
|
};
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#include "ball.h"
|
#include "ball.hpp"
|
||||||
|
|
||||||
#include <stdlib.h> // for rand
|
#include <stdlib.h> // for rand
|
||||||
|
|
||||||
#include <cmath> // for fabs
|
#include <cmath> // for fabs
|
||||||
|
|
||||||
#include "defines.h" // for Color, SCREEN_HEIGHT, GRAVITY_FORCE
|
#include "defines.hpp" // for Color, SCREEN_HEIGHT, GRAVITY_FORCE
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// Función auxiliar para generar pérdida aleatoria en rebotes
|
// Función auxiliar para generar pérdida aleatoria en rebotes
|
||||||
@@ -22,9 +22,9 @@ float generateLateralLoss() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Ball::Ball(float x, float vx, float vy, Color color, std::shared_ptr<Texture> texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir, float mass_factor)
|
Ball::Ball(float x, float y, float vx, float vy, Color color, std::shared_ptr<Texture> texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir, float mass_factor)
|
||||||
: sprite_(std::make_unique<Sprite>(texture)),
|
: sprite_(std::make_unique<Sprite>(texture)),
|
||||||
pos_({x, 0.0f, static_cast<float>(ball_size), static_cast<float>(ball_size)}) {
|
pos_({x, y, static_cast<float>(ball_size), static_cast<float>(ball_size)}) {
|
||||||
// Convertir velocidades de píxeles/frame a píxeles/segundo (multiplicar por 60)
|
// Convertir velocidades de píxeles/frame a píxeles/segundo (multiplicar por 60)
|
||||||
vx_ = vx * 60.0f;
|
vx_ = vx * 60.0f;
|
||||||
vy_ = vy * 60.0f;
|
vy_ = vy * 60.0f;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
#include <memory> // for shared_ptr, unique_ptr
|
#include <memory> // for shared_ptr, unique_ptr
|
||||||
|
|
||||||
#include "defines.h" // for Color
|
#include "defines.hpp" // for Color
|
||||||
#include "external/sprite.h" // for Sprite
|
#include "external/sprite.hpp" // for Sprite
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
class Ball {
|
class Ball {
|
||||||
@@ -31,7 +31,7 @@ class Ball {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
Ball(float x, float vx, float vy, Color color, std::shared_ptr<Texture> texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir = GravityDirection::DOWN, float mass_factor = 1.0f);
|
Ball(float x, float y, float vx, float vy, Color color, std::shared_ptr<Texture> texture, int screen_width, int screen_height, int ball_size, GravityDirection gravity_dir = GravityDirection::DOWN, float mass_factor = 1.0f);
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~Ball() = default;
|
~Ball() = default;
|
||||||
@@ -71,6 +71,13 @@ class Ball {
|
|||||||
GravityDirection getGravityDirection() const { return gravity_direction_; }
|
GravityDirection getGravityDirection() const { return gravity_direction_; }
|
||||||
bool isOnSurface() const { return on_surface_; }
|
bool isOnSurface() const { return on_surface_; }
|
||||||
|
|
||||||
|
// Getters/Setters para velocidad (usado por BoidManager)
|
||||||
|
void getVelocity(float& vx, float& vy) const { vx = vx_; vy = vy_; }
|
||||||
|
void setVelocity(float vx, float vy) { vx_ = vx; vy_ = vy; }
|
||||||
|
|
||||||
|
// Setter para posición simple (usado por BoidManager)
|
||||||
|
void setPosition(float x, float y) { pos_.x = x; pos_.y = y; }
|
||||||
|
|
||||||
// Getters/Setters para batch rendering
|
// Getters/Setters para batch rendering
|
||||||
SDL_FRect getPosition() const { return pos_; }
|
SDL_FRect getPosition() const { return pos_; }
|
||||||
Color getColor() const { return color_; }
|
Color getColor() const { return color_; }
|
||||||
404
source/boids_mgr/boid_manager.cpp
Normal file
404
source/boids_mgr/boid_manager.cpp
Normal file
@@ -0,0 +1,404 @@
|
|||||||
|
#include "boid_manager.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // for std::min, std::max
|
||||||
|
#include <cmath> // for sqrt, atan2
|
||||||
|
|
||||||
|
#include "ball.hpp" // for Ball
|
||||||
|
#include "engine.hpp" // for Engine (si se necesita)
|
||||||
|
#include "scene/scene_manager.hpp" // for SceneManager
|
||||||
|
#include "state/state_manager.hpp" // for StateManager
|
||||||
|
#include "ui/ui_manager.hpp" // for UIManager
|
||||||
|
|
||||||
|
BoidManager::BoidManager()
|
||||||
|
: engine_(nullptr)
|
||||||
|
, scene_mgr_(nullptr)
|
||||||
|
, ui_mgr_(nullptr)
|
||||||
|
, state_mgr_(nullptr)
|
||||||
|
, screen_width_(0)
|
||||||
|
, screen_height_(0)
|
||||||
|
, boids_active_(false)
|
||||||
|
, spatial_grid_(800, 600, BOID_GRID_CELL_SIZE) // Tamaño por defecto, se actualiza en initialize()
|
||||||
|
, separation_radius_(BOID_SEPARATION_RADIUS)
|
||||||
|
, alignment_radius_(BOID_ALIGNMENT_RADIUS)
|
||||||
|
, cohesion_radius_(BOID_COHESION_RADIUS)
|
||||||
|
, separation_weight_(BOID_SEPARATION_WEIGHT)
|
||||||
|
, alignment_weight_(BOID_ALIGNMENT_WEIGHT)
|
||||||
|
, cohesion_weight_(BOID_COHESION_WEIGHT)
|
||||||
|
, max_speed_(BOID_MAX_SPEED)
|
||||||
|
, min_speed_(BOID_MIN_SPEED)
|
||||||
|
, max_force_(BOID_MAX_FORCE)
|
||||||
|
, boundary_margin_(BOID_BOUNDARY_MARGIN)
|
||||||
|
, boundary_weight_(BOID_BOUNDARY_WEIGHT) {
|
||||||
|
}
|
||||||
|
|
||||||
|
BoidManager::~BoidManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::initialize(Engine* engine, SceneManager* scene_mgr, UIManager* ui_mgr,
|
||||||
|
StateManager* state_mgr, int screen_width, int screen_height) {
|
||||||
|
engine_ = engine;
|
||||||
|
scene_mgr_ = scene_mgr;
|
||||||
|
ui_mgr_ = ui_mgr;
|
||||||
|
state_mgr_ = state_mgr;
|
||||||
|
screen_width_ = screen_width;
|
||||||
|
screen_height_ = screen_height;
|
||||||
|
|
||||||
|
// Actualizar dimensiones del spatial grid
|
||||||
|
spatial_grid_.updateWorldSize(screen_width, screen_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::updateScreenSize(int width, int height) {
|
||||||
|
screen_width_ = width;
|
||||||
|
screen_height_ = height;
|
||||||
|
|
||||||
|
// Actualizar dimensiones del spatial grid (FASE 2)
|
||||||
|
spatial_grid_.updateWorldSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::activateBoids() {
|
||||||
|
boids_active_ = true;
|
||||||
|
|
||||||
|
// Desactivar gravedad al entrar en modo boids
|
||||||
|
scene_mgr_->forceBallsGravityOff();
|
||||||
|
|
||||||
|
// Inicializar velocidades aleatorias para los boids
|
||||||
|
auto& balls = scene_mgr_->getBallsMutable();
|
||||||
|
for (auto& ball : balls) {
|
||||||
|
// Dar velocidad inicial aleatoria si está quieto
|
||||||
|
float vx, vy;
|
||||||
|
ball->getVelocity(vx, vy);
|
||||||
|
if (vx == 0.0f && vy == 0.0f) {
|
||||||
|
// Velocidad aleatoria entre -60 y +60 px/s (time-based)
|
||||||
|
vx = ((rand() % 200 - 100) / 100.0f) * 60.0f;
|
||||||
|
vy = ((rand() % 200 - 100) / 100.0f) * 60.0f;
|
||||||
|
ball->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar notificación (solo si NO estamos en modo demo o logo)
|
||||||
|
if (state_mgr_ && ui_mgr_ && state_mgr_->getCurrentMode() == AppMode::SANDBOX) {
|
||||||
|
ui_mgr_->showNotification("Modo Boids");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::deactivateBoids(bool force_gravity_on) {
|
||||||
|
if (!boids_active_) return;
|
||||||
|
|
||||||
|
boids_active_ = false;
|
||||||
|
|
||||||
|
// Activar gravedad al salir (si se especifica)
|
||||||
|
if (force_gravity_on) {
|
||||||
|
scene_mgr_->forceBallsGravityOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostrar notificación (solo si NO estamos en modo demo o logo)
|
||||||
|
if (state_mgr_ && ui_mgr_ && state_mgr_->getCurrentMode() == AppMode::SANDBOX) {
|
||||||
|
ui_mgr_->showNotification("Modo Física");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::toggleBoidsMode(bool force_gravity_on) {
|
||||||
|
if (boids_active_) {
|
||||||
|
deactivateBoids(force_gravity_on);
|
||||||
|
} else {
|
||||||
|
activateBoids();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::update(float delta_time) {
|
||||||
|
if (!boids_active_) return;
|
||||||
|
|
||||||
|
auto& balls = scene_mgr_->getBallsMutable();
|
||||||
|
|
||||||
|
// FASE 2: Poblar spatial grid al inicio de cada frame (O(n))
|
||||||
|
spatial_grid_.clear();
|
||||||
|
for (auto& ball : balls) {
|
||||||
|
SDL_FRect pos = ball->getPosition();
|
||||||
|
float center_x = pos.x + pos.w / 2.0f;
|
||||||
|
float center_y = pos.y + pos.h / 2.0f;
|
||||||
|
spatial_grid_.insert(ball.get(), center_x, center_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aplicar las tres reglas de Reynolds a cada boid
|
||||||
|
// FASE 2: Ahora usa spatial grid para búsquedas O(1) en lugar de O(n)
|
||||||
|
for (auto& ball : balls) {
|
||||||
|
applySeparation(ball.get(), delta_time);
|
||||||
|
applyAlignment(ball.get(), delta_time);
|
||||||
|
applyCohesion(ball.get(), delta_time);
|
||||||
|
applyBoundaries(ball.get());
|
||||||
|
limitSpeed(ball.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualizar posiciones con velocidades resultantes (time-based)
|
||||||
|
for (auto& ball : balls) {
|
||||||
|
float vx, vy;
|
||||||
|
ball->getVelocity(vx, vy);
|
||||||
|
|
||||||
|
SDL_FRect pos = ball->getPosition();
|
||||||
|
pos.x += vx * delta_time; // time-based
|
||||||
|
pos.y += vy * delta_time;
|
||||||
|
|
||||||
|
ball->setPosition(pos.x, pos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// REGLAS DE REYNOLDS (1987)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
void BoidManager::applySeparation(Ball* boid, float delta_time) {
|
||||||
|
// Regla 1: Separación - Evitar colisiones con vecinos cercanos
|
||||||
|
float steer_x = 0.0f;
|
||||||
|
float steer_y = 0.0f;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
SDL_FRect pos = boid->getPosition();
|
||||||
|
float center_x = pos.x + pos.w / 2.0f;
|
||||||
|
float center_y = pos.y + pos.h / 2.0f;
|
||||||
|
|
||||||
|
// FASE 2: Usar spatial grid para buscar solo vecinos cercanos (O(1) en lugar de O(n))
|
||||||
|
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, separation_radius_);
|
||||||
|
|
||||||
|
for (Ball* other : neighbors) {
|
||||||
|
if (other == boid) continue; // Ignorar a sí mismo
|
||||||
|
|
||||||
|
SDL_FRect other_pos = other->getPosition();
|
||||||
|
float other_x = other_pos.x + other_pos.w / 2.0f;
|
||||||
|
float other_y = other_pos.y + other_pos.h / 2.0f;
|
||||||
|
|
||||||
|
float dx = center_x - other_x;
|
||||||
|
float dy = center_y - other_y;
|
||||||
|
float distance = std::sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance > 0.0f && distance < separation_radius_) {
|
||||||
|
// FASE 1.3: Separación más fuerte cuando más cerca (inversamente proporcional a distancia)
|
||||||
|
// Fuerza proporcional a cercanía: 0% en radio máximo, 100% en colisión
|
||||||
|
float separation_strength = (separation_radius_ - distance) / separation_radius_;
|
||||||
|
steer_x += (dx / distance) * separation_strength;
|
||||||
|
steer_y += (dy / distance) * separation_strength;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
// Promedio
|
||||||
|
steer_x /= count;
|
||||||
|
steer_y /= count;
|
||||||
|
|
||||||
|
// Aplicar fuerza de separación
|
||||||
|
float vx, vy;
|
||||||
|
boid->getVelocity(vx, vy);
|
||||||
|
vx += steer_x * separation_weight_ * delta_time;
|
||||||
|
vy += steer_y * separation_weight_ * delta_time;
|
||||||
|
boid->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::applyAlignment(Ball* boid, float delta_time) {
|
||||||
|
// Regla 2: Alineación - Seguir dirección promedio del grupo
|
||||||
|
float avg_vx = 0.0f;
|
||||||
|
float avg_vy = 0.0f;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
SDL_FRect pos = boid->getPosition();
|
||||||
|
float center_x = pos.x + pos.w / 2.0f;
|
||||||
|
float center_y = pos.y + pos.h / 2.0f;
|
||||||
|
|
||||||
|
// FASE 2: Usar spatial grid para buscar solo vecinos cercanos (O(1) en lugar de O(n))
|
||||||
|
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, alignment_radius_);
|
||||||
|
|
||||||
|
for (Ball* other : neighbors) {
|
||||||
|
if (other == boid) continue;
|
||||||
|
|
||||||
|
SDL_FRect other_pos = other->getPosition();
|
||||||
|
float other_x = other_pos.x + other_pos.w / 2.0f;
|
||||||
|
float other_y = other_pos.y + other_pos.h / 2.0f;
|
||||||
|
|
||||||
|
float dx = center_x - other_x;
|
||||||
|
float dy = center_y - other_y;
|
||||||
|
float distance = std::sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance < alignment_radius_) {
|
||||||
|
float other_vx, other_vy;
|
||||||
|
other->getVelocity(other_vx, other_vy);
|
||||||
|
avg_vx += other_vx;
|
||||||
|
avg_vy += other_vy;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
// Velocidad promedio del grupo
|
||||||
|
avg_vx /= count;
|
||||||
|
avg_vy /= count;
|
||||||
|
|
||||||
|
// Steering hacia la velocidad promedio
|
||||||
|
float vx, vy;
|
||||||
|
boid->getVelocity(vx, vy);
|
||||||
|
float steer_x = (avg_vx - vx) * alignment_weight_ * delta_time;
|
||||||
|
float steer_y = (avg_vy - vy) * alignment_weight_ * delta_time;
|
||||||
|
|
||||||
|
// Limitar fuerza máxima de steering
|
||||||
|
float steer_mag = std::sqrt(steer_x * steer_x + steer_y * steer_y);
|
||||||
|
if (steer_mag > max_force_) {
|
||||||
|
steer_x = (steer_x / steer_mag) * max_force_;
|
||||||
|
steer_y = (steer_y / steer_mag) * max_force_;
|
||||||
|
}
|
||||||
|
|
||||||
|
vx += steer_x;
|
||||||
|
vy += steer_y;
|
||||||
|
boid->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::applyCohesion(Ball* boid, float delta_time) {
|
||||||
|
// Regla 3: Cohesión - Moverse hacia el centro de masa del grupo
|
||||||
|
float center_of_mass_x = 0.0f;
|
||||||
|
float center_of_mass_y = 0.0f;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
SDL_FRect pos = boid->getPosition();
|
||||||
|
float center_x = pos.x + pos.w / 2.0f;
|
||||||
|
float center_y = pos.y + pos.h / 2.0f;
|
||||||
|
|
||||||
|
// FASE 2: Usar spatial grid para buscar solo vecinos cercanos (O(1) en lugar de O(n))
|
||||||
|
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, cohesion_radius_);
|
||||||
|
|
||||||
|
for (Ball* other : neighbors) {
|
||||||
|
if (other == boid) continue;
|
||||||
|
|
||||||
|
SDL_FRect other_pos = other->getPosition();
|
||||||
|
float other_x = other_pos.x + other_pos.w / 2.0f;
|
||||||
|
float other_y = other_pos.y + other_pos.h / 2.0f;
|
||||||
|
|
||||||
|
float dx = center_x - other_x;
|
||||||
|
float dy = center_y - other_y;
|
||||||
|
float distance = std::sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance < cohesion_radius_) {
|
||||||
|
center_of_mass_x += other_x;
|
||||||
|
center_of_mass_y += other_y;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
// Centro de masa del grupo
|
||||||
|
center_of_mass_x /= count;
|
||||||
|
center_of_mass_y /= count;
|
||||||
|
|
||||||
|
// FASE 1.4: Normalizar dirección hacia el centro (CRÍTICO - antes no estaba normalizado!)
|
||||||
|
float dx_to_center = center_of_mass_x - center_x;
|
||||||
|
float dy_to_center = center_of_mass_y - center_y;
|
||||||
|
float distance_to_center = std::sqrt(dx_to_center * dx_to_center + dy_to_center * dy_to_center);
|
||||||
|
|
||||||
|
// Solo aplicar si hay distancia al centro (evitar división por cero)
|
||||||
|
if (distance_to_center > 0.1f) {
|
||||||
|
// Normalizar vector dirección (fuerza independiente de distancia)
|
||||||
|
float steer_x = (dx_to_center / distance_to_center) * cohesion_weight_ * delta_time;
|
||||||
|
float steer_y = (dy_to_center / distance_to_center) * cohesion_weight_ * delta_time;
|
||||||
|
|
||||||
|
// Limitar fuerza máxima de steering
|
||||||
|
float steer_mag = std::sqrt(steer_x * steer_x + steer_y * steer_y);
|
||||||
|
if (steer_mag > max_force_) {
|
||||||
|
steer_x = (steer_x / steer_mag) * max_force_;
|
||||||
|
steer_y = (steer_y / steer_mag) * max_force_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float vx, vy;
|
||||||
|
boid->getVelocity(vx, vy);
|
||||||
|
vx += steer_x;
|
||||||
|
vy += steer_y;
|
||||||
|
boid->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::applyBoundaries(Ball* boid) {
|
||||||
|
// NUEVA IMPLEMENTACIÓN: Bordes como obstáculos (repulsión en lugar de wrapping)
|
||||||
|
// Cuando un boid se acerca a un borde, se aplica una fuerza alejándolo
|
||||||
|
SDL_FRect pos = boid->getPosition();
|
||||||
|
float center_x = pos.x + pos.w / 2.0f;
|
||||||
|
float center_y = pos.y + pos.h / 2.0f;
|
||||||
|
|
||||||
|
float steer_x = 0.0f;
|
||||||
|
float steer_y = 0.0f;
|
||||||
|
|
||||||
|
// Borde izquierdo (x < boundary_margin_)
|
||||||
|
if (center_x < boundary_margin_) {
|
||||||
|
float distance = center_x; // Distancia al borde (0 = colisión)
|
||||||
|
if (distance < boundary_margin_) {
|
||||||
|
// Fuerza proporcional a cercanía: 0% en margen, 100% en colisión
|
||||||
|
float repulsion_strength = (boundary_margin_ - distance) / boundary_margin_;
|
||||||
|
steer_x += repulsion_strength; // Empujar hacia la derecha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borde derecho (x > screen_width_ - boundary_margin_)
|
||||||
|
if (center_x > screen_width_ - boundary_margin_) {
|
||||||
|
float distance = screen_width_ - center_x;
|
||||||
|
if (distance < boundary_margin_) {
|
||||||
|
float repulsion_strength = (boundary_margin_ - distance) / boundary_margin_;
|
||||||
|
steer_x -= repulsion_strength; // Empujar hacia la izquierda
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borde superior (y < boundary_margin_)
|
||||||
|
if (center_y < boundary_margin_) {
|
||||||
|
float distance = center_y;
|
||||||
|
if (distance < boundary_margin_) {
|
||||||
|
float repulsion_strength = (boundary_margin_ - distance) / boundary_margin_;
|
||||||
|
steer_y += repulsion_strength; // Empujar hacia abajo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borde inferior (y > screen_height_ - boundary_margin_)
|
||||||
|
if (center_y > screen_height_ - boundary_margin_) {
|
||||||
|
float distance = screen_height_ - center_y;
|
||||||
|
if (distance < boundary_margin_) {
|
||||||
|
float repulsion_strength = (boundary_margin_ - distance) / boundary_margin_;
|
||||||
|
steer_y -= repulsion_strength; // Empujar hacia arriba
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aplicar fuerza de repulsión si hay alguna
|
||||||
|
if (steer_x != 0.0f || steer_y != 0.0f) {
|
||||||
|
float vx, vy;
|
||||||
|
boid->getVelocity(vx, vy);
|
||||||
|
|
||||||
|
// Normalizar fuerza de repulsión (para que todas las direcciones tengan la misma intensidad)
|
||||||
|
float steer_mag = std::sqrt(steer_x * steer_x + steer_y * steer_y);
|
||||||
|
if (steer_mag > 0.0f) {
|
||||||
|
steer_x /= steer_mag;
|
||||||
|
steer_y /= steer_mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aplicar aceleración de repulsión (time-based)
|
||||||
|
// boundary_weight_ es más fuerte que separation para garantizar que no escapen
|
||||||
|
vx += steer_x * boundary_weight_ * (1.0f / 60.0f); // Simular delta_time fijo para independencia
|
||||||
|
vy += steer_y * boundary_weight_ * (1.0f / 60.0f);
|
||||||
|
boid->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoidManager::limitSpeed(Ball* boid) {
|
||||||
|
// Limitar velocidad máxima del boid
|
||||||
|
float vx, vy;
|
||||||
|
boid->getVelocity(vx, vy);
|
||||||
|
|
||||||
|
float speed = std::sqrt(vx * vx + vy * vy);
|
||||||
|
|
||||||
|
// Limitar velocidad máxima
|
||||||
|
if (speed > max_speed_) {
|
||||||
|
vx = (vx / speed) * max_speed_;
|
||||||
|
vy = (vy / speed) * max_speed_;
|
||||||
|
boid->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FASE 1.2: Aplicar velocidad mínima (evitar boids estáticos)
|
||||||
|
if (speed > 0.0f && speed < min_speed_) {
|
||||||
|
vx = (vx / speed) * min_speed_;
|
||||||
|
vy = (vy / speed) * min_speed_;
|
||||||
|
boid->setVelocity(vx, vy);
|
||||||
|
}
|
||||||
|
}
|
||||||
126
source/boids_mgr/boid_manager.hpp
Normal file
126
source/boids_mgr/boid_manager.hpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // for size_t
|
||||||
|
|
||||||
|
#include "defines.hpp" // for SimulationMode, AppMode
|
||||||
|
#include "spatial_grid.hpp" // for SpatialGrid
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Engine;
|
||||||
|
class SceneManager;
|
||||||
|
class UIManager;
|
||||||
|
class StateManager;
|
||||||
|
class Ball;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class BoidManager
|
||||||
|
* @brief Gestiona el comportamiento de enjambre (boids)
|
||||||
|
*
|
||||||
|
* Responsabilidad única: Implementación de algoritmo de boids (Reynolds 1987)
|
||||||
|
*
|
||||||
|
* Características:
|
||||||
|
* - Separación: Evitar colisiones con vecinos cercanos
|
||||||
|
* - Alineación: Seguir dirección promedio del grupo
|
||||||
|
* - Cohesión: Moverse hacia el centro de masa del grupo
|
||||||
|
* - Comportamiento emergente sin control centralizado
|
||||||
|
* - Física de steering behavior (velocidad limitada)
|
||||||
|
*/
|
||||||
|
class BoidManager {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
BoidManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
~BoidManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inicializa el BoidManager con referencias a componentes del Engine
|
||||||
|
* @param engine Puntero al Engine (para acceso a recursos)
|
||||||
|
* @param scene_mgr Puntero a SceneManager (acceso a bolas)
|
||||||
|
* @param ui_mgr Puntero a UIManager (notificaciones)
|
||||||
|
* @param state_mgr Puntero a StateManager (estados de aplicación)
|
||||||
|
* @param screen_width Ancho de pantalla actual
|
||||||
|
* @param screen_height Alto de pantalla actual
|
||||||
|
*/
|
||||||
|
void initialize(Engine* engine, SceneManager* scene_mgr, UIManager* ui_mgr,
|
||||||
|
StateManager* state_mgr, int screen_width, int screen_height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actualiza el tamaño de pantalla (llamado en resize/fullscreen)
|
||||||
|
* @param width Nuevo ancho de pantalla
|
||||||
|
* @param height Nuevo alto de pantalla
|
||||||
|
*/
|
||||||
|
void updateScreenSize(int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Activa el modo boids
|
||||||
|
*/
|
||||||
|
void activateBoids();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Desactiva el modo boids (vuelve a física normal)
|
||||||
|
* @param force_gravity_on Si debe forzar gravedad ON al salir
|
||||||
|
*/
|
||||||
|
void deactivateBoids(bool force_gravity_on = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Toggle entre modo boids y modo física
|
||||||
|
* @param force_gravity_on Si debe forzar gravedad ON al salir de boids
|
||||||
|
*/
|
||||||
|
void toggleBoidsMode(bool force_gravity_on = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actualiza el comportamiento de todas las bolas como boids
|
||||||
|
* @param delta_time Delta time para física
|
||||||
|
*/
|
||||||
|
void update(float delta_time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verifica si el modo boids está activo
|
||||||
|
* @return true si modo boids está activo
|
||||||
|
*/
|
||||||
|
bool isBoidsActive() const { return boids_active_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Referencias a componentes del Engine
|
||||||
|
Engine* engine_;
|
||||||
|
SceneManager* scene_mgr_;
|
||||||
|
UIManager* ui_mgr_;
|
||||||
|
StateManager* state_mgr_;
|
||||||
|
|
||||||
|
// Tamaño de pantalla
|
||||||
|
int screen_width_;
|
||||||
|
int screen_height_;
|
||||||
|
|
||||||
|
// Estado del modo boids
|
||||||
|
bool boids_active_;
|
||||||
|
|
||||||
|
// Spatial Hash Grid para optimización O(n²) → O(n)
|
||||||
|
// FASE 2: Grid reutilizable para búsquedas de vecinos
|
||||||
|
SpatialGrid spatial_grid_;
|
||||||
|
|
||||||
|
// === Parámetros ajustables en runtime (inicializados con valores de defines.h) ===
|
||||||
|
// Permite modificar comportamiento sin recompilar (para tweaking/debug visual)
|
||||||
|
float separation_radius_; // Radio de separación (evitar colisiones)
|
||||||
|
float alignment_radius_; // Radio de alineación (matching de velocidad)
|
||||||
|
float cohesion_radius_; // Radio de cohesión (centro de masa)
|
||||||
|
float separation_weight_; // Peso fuerza de separación (aceleración px/s²)
|
||||||
|
float alignment_weight_; // Peso fuerza de alineación (steering proporcional)
|
||||||
|
float cohesion_weight_; // Peso fuerza de cohesión (aceleración px/s²)
|
||||||
|
float max_speed_; // Velocidad máxima (px/s)
|
||||||
|
float min_speed_; // Velocidad mínima (px/s)
|
||||||
|
float max_force_; // Fuerza máxima de steering (px/s)
|
||||||
|
float boundary_margin_; // Margen para repulsión de bordes (px)
|
||||||
|
float boundary_weight_; // Peso fuerza de repulsión de bordes (aceleración px/s²)
|
||||||
|
|
||||||
|
// Métodos privados para las reglas de Reynolds
|
||||||
|
void applySeparation(Ball* boid, float delta_time);
|
||||||
|
void applyAlignment(Ball* boid, float delta_time);
|
||||||
|
void applyCohesion(Ball* boid, float delta_time);
|
||||||
|
void applyBoundaries(Ball* boid); // Repulsión de bordes (ya no wrapping)
|
||||||
|
void limitSpeed(Ball* boid); // Limitar velocidad máxima
|
||||||
|
};
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
constexpr char WINDOW_CAPTION[] = "ViBe3 Physics (JailDesigner 2025)";
|
constexpr char WINDOW_CAPTION[] = "ViBe3 Physics (JailDesigner 2025)";
|
||||||
|
|
||||||
// Resolución por defecto (usada si no se especifica en CLI)
|
// Resolución por defecto (usada si no se especifica en CLI)
|
||||||
constexpr int DEFAULT_SCREEN_WIDTH = 320; // Ancho lógico por defecto (si no hay -w)
|
constexpr int DEFAULT_SCREEN_WIDTH = 1280; // Ancho lógico por defecto (si no hay -w)
|
||||||
constexpr int DEFAULT_SCREEN_HEIGHT = 240; // Alto lógico por defecto (si no hay -h)
|
constexpr int DEFAULT_SCREEN_HEIGHT = 720; // Alto lógico por defecto (si no hay -h)
|
||||||
constexpr int DEFAULT_WINDOW_ZOOM = 3; // Zoom inicial de ventana (1x = sin zoom)
|
constexpr int DEFAULT_WINDOW_ZOOM = 1; // Zoom inicial de ventana (1x = sin zoom)
|
||||||
|
|
||||||
// Configuración de zoom dinámico de ventana
|
// Configuración de zoom dinámico de ventana
|
||||||
constexpr int WINDOW_ZOOM_MIN = 1; // Zoom mínimo (320x240)
|
constexpr int WINDOW_ZOOM_MIN = 1; // Zoom mínimo (320x240)
|
||||||
@@ -22,9 +22,18 @@ constexpr int WINDOW_DECORATION_HEIGHT = 30; // Altura estimada de decoraciones
|
|||||||
constexpr float GRAVITY_FORCE = 0.2f; // Fuerza de gravedad (píxeles/frame²)
|
constexpr float GRAVITY_FORCE = 0.2f; // Fuerza de gravedad (píxeles/frame²)
|
||||||
|
|
||||||
// Configuración de interfaz
|
// Configuración de interfaz
|
||||||
constexpr Uint64 TEXT_DURATION = 2000; // Duración del texto informativo (ms)
|
|
||||||
constexpr float THEME_TRANSITION_DURATION = 0.5f; // Duración de transiciones LERP entre temas (segundos)
|
constexpr float THEME_TRANSITION_DURATION = 0.5f; // Duración de transiciones LERP entre temas (segundos)
|
||||||
|
|
||||||
|
// Configuración de notificaciones (sistema Notifier)
|
||||||
|
constexpr int TEXT_ABSOLUTE_SIZE = 12; // Tamaño fuente base en píxeles físicos (múltiplo de 12px, tamaño nativo de la fuente)
|
||||||
|
constexpr Uint64 NOTIFICATION_DURATION = 2000; // Duración default de notificaciones (ms)
|
||||||
|
constexpr Uint64 NOTIFICATION_SLIDE_TIME = 300; // Duración animación entrada (ms)
|
||||||
|
constexpr Uint64 NOTIFICATION_FADE_TIME = 200; // Duración animación salida (ms)
|
||||||
|
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_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
|
||||||
constexpr float BOUNCE_RANDOM_LOSS_PERCENT = 0.1f; // 0-10% pérdida adicional aleatoria en cada rebote
|
constexpr float BOUNCE_RANDOM_LOSS_PERCENT = 0.1f; // 0-10% pérdida adicional aleatoria en cada rebote
|
||||||
@@ -44,6 +53,14 @@ constexpr float BALL_SPAWN_MARGIN = 0.15f; // Margen lateral para spawn (0.25 =
|
|||||||
// Escenarios de número de pelotas (teclas 1-8)
|
// Escenarios de número de pelotas (teclas 1-8)
|
||||||
constexpr int BALL_COUNT_SCENARIOS[8] = {10, 50, 100, 500, 1000, 5000, 10000, 50000};
|
constexpr int BALL_COUNT_SCENARIOS[8] = {10, 50, 100, 500, 1000, 5000, 10000, 50000};
|
||||||
|
|
||||||
|
// Límites de escenario para modos automáticos (índices en BALL_COUNT_SCENARIOS)
|
||||||
|
// BALL_COUNT_SCENARIOS = {10, 50, 100, 500, 1000, 5000, 10000, 50000}
|
||||||
|
// 0 1 2 3 4 5 6 7
|
||||||
|
constexpr int DEMO_AUTO_MIN_SCENARIO = 2; // mínimo 100 bolas
|
||||||
|
constexpr int DEMO_AUTO_MAX_SCENARIO = 7; // máximo sin restricción hardware (ajustado por benchmark)
|
||||||
|
constexpr int LOGO_MIN_SCENARIO_IDX = 4; // mínimo 1000 bolas (sustituye LOGO_MODE_MIN_BALLS)
|
||||||
|
constexpr int CUSTOM_SCENARIO_IDX = 8; // Escenario custom opcional (tecla 9, --custom-balls)
|
||||||
|
|
||||||
// Estructura para representar colores RGB
|
// Estructura para representar colores RGB
|
||||||
struct Color {
|
struct Color {
|
||||||
int r, g, b; // Componentes rojo, verde, azul (0-255)
|
int r, g, b; // Componentes rojo, verde, azul (0-255)
|
||||||
@@ -51,12 +68,12 @@ struct Color {
|
|||||||
|
|
||||||
// Estructura de tema de colores estático
|
// Estructura de tema de colores estático
|
||||||
struct ThemeColors {
|
struct ThemeColors {
|
||||||
const char* name_en; // Nombre en inglés (para debug)
|
const char* name_en; // Nombre en inglés (para debug)
|
||||||
const char* name_es; // Nombre en español (para display)
|
const char* name_es; // Nombre en español (para display)
|
||||||
int text_color_r, text_color_g, text_color_b; // Color del texto del tema
|
int text_color_r, text_color_g, text_color_b; // Color del texto del tema
|
||||||
float bg_top_r, bg_top_g, bg_top_b;
|
float bg_top_r, bg_top_g, bg_top_b;
|
||||||
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
||||||
std::vector<Color> ball_colors;
|
std::vector<Color> ball_colors;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para keyframe de tema dinámico
|
// Estructura para keyframe de tema dinámico
|
||||||
@@ -65,6 +82,9 @@ struct DynamicThemeKeyframe {
|
|||||||
float bg_top_r, bg_top_g, bg_top_b;
|
float bg_top_r, bg_top_g, bg_top_b;
|
||||||
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
||||||
|
|
||||||
|
// Color de fondo de notificaciones
|
||||||
|
int notif_bg_r, notif_bg_g, notif_bg_b;
|
||||||
|
|
||||||
// Colores de pelotas en este keyframe
|
// Colores de pelotas en este keyframe
|
||||||
std::vector<Color> ball_colors;
|
std::vector<Color> ball_colors;
|
||||||
|
|
||||||
@@ -84,19 +104,24 @@ enum class GravityDirection {
|
|||||||
RIGHT // → Gravedad hacia la derecha
|
RIGHT // → Gravedad hacia la derecha
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enum para temas de colores (seleccionables con teclado numérico)
|
// Enum para temas de colores (seleccionables con teclado numérico y Shift+Numpad)
|
||||||
// Todos los temas usan ahora sistema dinámico de keyframes
|
// Todos los temas usan ahora sistema dinámico de keyframes
|
||||||
enum class ColorTheme {
|
enum class ColorTheme {
|
||||||
SUNSET = 0, // Naranjas, rojos, amarillos, rosas (estático: 1 keyframe)
|
SUNSET = 0, // Naranjas, rojos, amarillos, rosas (estático: 1 keyframe)
|
||||||
OCEAN = 1, // Azules, turquesas, blancos (estático: 1 keyframe)
|
OCEAN = 1, // Azules, turquesas, blancos (estático: 1 keyframe)
|
||||||
NEON = 2, // Cian, magenta, verde lima, amarillo vibrante (estático: 1 keyframe)
|
NEON = 2, // Cian, magenta, verde lima, amarillo vibrante (estático: 1 keyframe)
|
||||||
FOREST = 3, // Verdes, marrones, amarillos otoño (estático: 1 keyframe)
|
FOREST = 3, // Verdes, marrones, amarillos otoño (estático: 1 keyframe)
|
||||||
RGB = 4, // RGB puros y subdivisiones matemáticas - fondo blanco (estático: 1 keyframe)
|
RGB = 4, // RGB puros y subdivisiones matemáticas - fondo blanco (estático: 1 keyframe)
|
||||||
MONOCHROME = 5, // Fondo negro degradado, sprites blancos monocromáticos (estático: 1 keyframe)
|
MONOCHROME = 5, // Fondo negro degradado, sprites blancos monocromáticos (estático: 1 keyframe)
|
||||||
LAVENDER = 6, // Degradado violeta-azul, pelotas amarillo dorado (estático: 1 keyframe)
|
LAVENDER = 6, // Degradado violeta-azul, pelotas amarillo dorado (estático: 1 keyframe)
|
||||||
SUNRISE = 7, // Amanecer: Noche → Alba → Día (animado: 4 keyframes, 12s ciclo)
|
CRIMSON = 7, // Fondo negro-rojo, pelotas rojas uniformes (estático: 1 keyframe)
|
||||||
OCEAN_WAVES = 8, // Olas oceánicas: Azul oscuro ↔ Turquesa (animado: 3 keyframes, 8s ciclo)
|
EMERALD = 8, // Fondo negro-verde, pelotas verdes uniformes (estático: 1 keyframe)
|
||||||
NEON_PULSE = 9 // Pulso neón: Negro ↔ Neón vibrante (animado: 3 keyframes, 3s ping-pong)
|
SUNRISE = 9, // Amanecer: Noche → Alba → Día (animado: 4 keyframes, 12s ciclo)
|
||||||
|
OCEAN_WAVES = 10, // Olas oceánicas: Azul oscuro ↔ Turquesa (animado: 3 keyframes, 8s ciclo)
|
||||||
|
NEON_PULSE = 11, // Pulso neón: Negro ↔ Neón vibrante (animado: 3 keyframes, 3s ping-pong)
|
||||||
|
FIRE = 12, // Fuego vivo: Brasas → Llamas → Inferno (animado: 4 keyframes, 10s ciclo)
|
||||||
|
AURORA = 13, // Aurora boreal: Verde → Violeta → Cian (animado: 4 keyframes, 14s ciclo)
|
||||||
|
VOLCANIC = 14 // Erupción volcánica: Ceniza → Erupción → Lava (animado: 4 keyframes, 12s ciclo)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enum para tipo de figura 3D
|
// Enum para tipo de figura 3D
|
||||||
@@ -116,7 +141,16 @@ enum class ShapeType {
|
|||||||
// Enum para modo de simulación
|
// Enum para modo de simulación
|
||||||
enum class SimulationMode {
|
enum class SimulationMode {
|
||||||
PHYSICS, // Modo física normal con gravedad
|
PHYSICS, // Modo física normal con gravedad
|
||||||
SHAPE // Modo figura 3D (Shape polimórfico)
|
SHAPE, // Modo figura 3D (Shape polimórfico)
|
||||||
|
BOIDS // Modo enjambre (Boids - comportamiento emergente)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enum para modo de aplicación (mutuamente excluyentes)
|
||||||
|
enum class AppMode {
|
||||||
|
SANDBOX, // Control manual del usuario (modo sandbox)
|
||||||
|
DEMO, // Modo demo completo (auto-play)
|
||||||
|
DEMO_LITE, // Modo demo lite (solo física/figuras)
|
||||||
|
LOGO // Modo logo (easter egg)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enum para modo de escalado en fullscreen (F5)
|
// Enum para modo de escalado en fullscreen (F5)
|
||||||
@@ -256,11 +290,42 @@ constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO = 5; // 5% probabilidad en D
|
|||||||
constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE = 3; // 3% probabilidad en DEMO LITE (aún más raro)
|
constexpr int LOGO_JUMP_PROBABILITY_FROM_DEMO_LITE = 3; // 3% probabilidad en DEMO LITE (aún más raro)
|
||||||
|
|
||||||
// Sistema de espera de flips en LOGO MODE (camino alternativo de decisión)
|
// Sistema de espera de flips en LOGO MODE (camino alternativo de decisión)
|
||||||
constexpr int LOGO_FLIP_WAIT_MIN = 1; // Mínimo de flips a esperar antes de cambiar a PHYSICS
|
constexpr int LOGO_FLIP_WAIT_MIN = 1; // Mínimo de flips a esperar antes de cambiar a PHYSICS
|
||||||
constexpr int LOGO_FLIP_WAIT_MAX = 3; // Máximo de flips a esperar
|
constexpr int LOGO_FLIP_WAIT_MAX = 3; // Máximo de flips a esperar
|
||||||
constexpr float LOGO_FLIP_TRIGGER_MIN = 0.20f; // 20% mínimo de progreso de flip para trigger
|
constexpr float LOGO_FLIP_TRIGGER_MIN = 0.20f; // 20% mínimo de progreso de flip para trigger
|
||||||
constexpr float LOGO_FLIP_TRIGGER_MAX = 0.80f; // 80% máximo de progreso de flip para trigger
|
constexpr float LOGO_FLIP_TRIGGER_MAX = 0.80f; // 80% máximo de progreso de flip para trigger
|
||||||
constexpr int LOGO_FLIP_WAIT_PROBABILITY = 50; // 50% probabilidad de elegir el camino "esperar flip"
|
constexpr int LOGO_FLIP_WAIT_PROBABILITY = 50; // 50% probabilidad de elegir el camino "esperar flip"
|
||||||
|
|
||||||
|
// Configuración de AppLogo (logo periódico en pantalla)
|
||||||
|
constexpr float APPLOGO_DISPLAY_INTERVAL = 90.0f; // Intervalo entre apariciones del logo (segundos)
|
||||||
|
constexpr float APPLOGO_DISPLAY_DURATION = 30.0f; // Duración de visibilidad del logo (segundos)
|
||||||
|
constexpr float APPLOGO_ANIMATION_DURATION = 0.5f; // Duración de animación entrada/salida (segundos)
|
||||||
|
constexpr float APPLOGO_HEIGHT_PERCENT = 0.4f; // Altura del logo = 40% de la altura de pantalla
|
||||||
|
constexpr float APPLOGO_PADDING_PERCENT = 0.05f; // Padding desde esquina inferior-derecha = 10%
|
||||||
|
constexpr float APPLOGO_LOGO2_DELAY = 0.25f; // Retraso de Logo 2 respecto a Logo 1 (segundos)
|
||||||
|
|
||||||
|
// Configuración de Modo BOIDS (comportamiento de enjambre)
|
||||||
|
// TIME-BASED CONVERSION (frame-based → time-based):
|
||||||
|
// - Radios: sin cambios (píxeles)
|
||||||
|
// - Velocidades (MAX_SPEED, MIN_SPEED): ×60 (px/frame → px/s)
|
||||||
|
// - Aceleraciones puras (SEPARATION, COHESION): ×60² = ×3600 (px/frame² → px/s²)
|
||||||
|
// - Steering proporcional (ALIGNMENT): ×60 (proporcional a velocidad)
|
||||||
|
// - Límite velocidad (MAX_FORCE): ×60 (px/frame → px/s)
|
||||||
|
constexpr float BOID_SEPARATION_RADIUS = 30.0f; // Radio para evitar colisiones (píxeles)
|
||||||
|
constexpr float BOID_ALIGNMENT_RADIUS = 50.0f; // Radio para alinear velocidad con vecinos
|
||||||
|
constexpr float BOID_COHESION_RADIUS = 80.0f; // Radio para moverse hacia centro del grupo
|
||||||
|
constexpr float BOID_SEPARATION_WEIGHT = 5400.0f; // Aceleración de separación (px/s²) [era 1.5 × 3600]
|
||||||
|
constexpr float BOID_ALIGNMENT_WEIGHT = 60.0f; // Steering de alineación (proporcional) [era 1.0 × 60]
|
||||||
|
constexpr float BOID_COHESION_WEIGHT = 3.6f; // Aceleración de cohesión (px/s²) [era 0.001 × 3600]
|
||||||
|
constexpr float BOID_MAX_SPEED = 150.0f; // Velocidad máxima (px/s) [era 2.5 × 60]
|
||||||
|
constexpr float BOID_MAX_FORCE = 3.0f; // Fuerza máxima de steering (px/s) [era 0.05 × 60]
|
||||||
|
constexpr float BOID_MIN_SPEED = 18.0f; // Velocidad mínima (px/s) [era 0.3 × 60]
|
||||||
|
constexpr float BOID_BOUNDARY_MARGIN = 50.0f; // Distancia a borde para activar repulsión (píxeles)
|
||||||
|
constexpr float BOID_BOUNDARY_WEIGHT = 7200.0f; // Aceleración de repulsión de bordes (px/s²) [más fuerte que separation]
|
||||||
|
|
||||||
|
// FASE 2: Spatial Hash Grid para optimización O(n²) → O(n)
|
||||||
|
constexpr float BOID_GRID_CELL_SIZE = 100.0f; // Tamaño de celda del grid (píxeles)
|
||||||
|
// Debe ser ≥ BOID_COHESION_RADIUS para funcionar correctamente
|
||||||
|
|
||||||
constexpr float PI = 3.14159265358979323846f; // Constante PI
|
constexpr float PI = 3.14159265358979323846f; // Constante PI
|
||||||
|
|
||||||
1870
source/engine.cpp
1870
source/engine.cpp
File diff suppressed because it is too large
Load Diff
175
source/engine.h
175
source/engine.h
@@ -1,175 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <SDL3/SDL_events.h> // for SDL_Event
|
|
||||||
#include <SDL3/SDL_render.h> // for SDL_Renderer
|
|
||||||
#include <SDL3/SDL_stdinc.h> // for Uint64
|
|
||||||
#include <SDL3/SDL_video.h> // for SDL_Window
|
|
||||||
|
|
||||||
#include <array> // for array
|
|
||||||
#include <memory> // for unique_ptr, shared_ptr
|
|
||||||
#include <string> // for string
|
|
||||||
#include <vector> // for vector
|
|
||||||
|
|
||||||
#include "ball.h" // for Ball
|
|
||||||
#include "defines.h" // for GravityDirection, ColorTheme, ShapeType
|
|
||||||
#include "external/texture.h" // for Texture
|
|
||||||
#include "shapes/shape.h" // for Shape (interfaz polimórfica)
|
|
||||||
#include "theme_manager.h" // for ThemeManager
|
|
||||||
|
|
||||||
// Modos de aplicación mutuamente excluyentes
|
|
||||||
enum class AppMode {
|
|
||||||
MANUAL, // Control manual del usuario
|
|
||||||
DEMO, // Modo demo completo (auto-play)
|
|
||||||
DEMO_LITE, // Modo demo lite (solo física/figuras)
|
|
||||||
LOGO // Modo logo (easter egg)
|
|
||||||
};
|
|
||||||
|
|
||||||
class Engine {
|
|
||||||
public:
|
|
||||||
// Interfaz pública
|
|
||||||
bool initialize(int width = 0, int height = 0, int zoom = 0, bool fullscreen = false);
|
|
||||||
void run();
|
|
||||||
void shutdown();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Recursos SDL
|
|
||||||
SDL_Window* window_ = nullptr;
|
|
||||||
SDL_Renderer* renderer_ = nullptr;
|
|
||||||
std::shared_ptr<Texture> texture_ = nullptr; // Textura activa actual
|
|
||||||
std::vector<std::shared_ptr<Texture>> textures_; // Todas las texturas disponibles
|
|
||||||
std::vector<std::string> texture_names_; // Nombres de texturas (sin extensión)
|
|
||||||
size_t current_texture_index_ = 0; // Índice de textura activa
|
|
||||||
int current_ball_size_ = 10; // Tamaño actual de pelotas (dinámico, se actualiza desde texture)
|
|
||||||
|
|
||||||
// Estado del simulador
|
|
||||||
std::vector<std::unique_ptr<Ball>> balls_;
|
|
||||||
GravityDirection current_gravity_ = GravityDirection::DOWN;
|
|
||||||
int scenario_ = 0;
|
|
||||||
bool should_exit_ = false;
|
|
||||||
|
|
||||||
// Sistema de timing
|
|
||||||
Uint64 last_frame_time_ = 0;
|
|
||||||
float delta_time_ = 0.0f;
|
|
||||||
|
|
||||||
// UI y debug
|
|
||||||
bool show_debug_ = false;
|
|
||||||
bool show_text_ = true;
|
|
||||||
|
|
||||||
// Sistema de zoom dinámico
|
|
||||||
int current_window_zoom_ = DEFAULT_WINDOW_ZOOM;
|
|
||||||
std::string text_;
|
|
||||||
int text_pos_ = 0;
|
|
||||||
Uint64 text_init_time_ = 0;
|
|
||||||
|
|
||||||
// FPS y V-Sync
|
|
||||||
Uint64 fps_last_time_ = 0;
|
|
||||||
int fps_frame_count_ = 0;
|
|
||||||
int fps_current_ = 0;
|
|
||||||
std::string fps_text_ = "FPS: 0";
|
|
||||||
bool vsync_enabled_ = true;
|
|
||||||
std::string vsync_text_ = "VSYNC ON";
|
|
||||||
bool fullscreen_enabled_ = false;
|
|
||||||
bool real_fullscreen_enabled_ = false;
|
|
||||||
ScalingMode current_scaling_mode_ = ScalingMode::INTEGER; // Modo de escalado actual (F5)
|
|
||||||
|
|
||||||
// Resolución base (configurada por CLI o default)
|
|
||||||
int base_screen_width_ = DEFAULT_SCREEN_WIDTH;
|
|
||||||
int base_screen_height_ = DEFAULT_SCREEN_HEIGHT;
|
|
||||||
|
|
||||||
// Resolución dinámica actual (cambia en fullscreen real)
|
|
||||||
int current_screen_width_ = DEFAULT_SCREEN_WIDTH;
|
|
||||||
int current_screen_height_ = DEFAULT_SCREEN_HEIGHT;
|
|
||||||
|
|
||||||
// Sistema de temas (delegado a ThemeManager)
|
|
||||||
std::unique_ptr<ThemeManager> theme_manager_;
|
|
||||||
|
|
||||||
// Sistema de Figuras 3D (polimórfico)
|
|
||||||
SimulationMode current_mode_ = SimulationMode::PHYSICS;
|
|
||||||
ShapeType current_shape_type_ = ShapeType::SPHERE; // Tipo de figura actual
|
|
||||||
ShapeType last_shape_type_ = ShapeType::SPHERE; // Última figura para toggle F
|
|
||||||
std::unique_ptr<Shape> active_shape_; // Puntero polimórfico a figura activa
|
|
||||||
float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-)
|
|
||||||
bool depth_zoom_enabled_ = true; // Zoom por profundidad Z activado
|
|
||||||
|
|
||||||
// Sistema de Modo DEMO (auto-play)
|
|
||||||
AppMode current_app_mode_ = AppMode::MANUAL; // Modo actual (mutuamente excluyente)
|
|
||||||
AppMode previous_app_mode_ = AppMode::MANUAL; // Modo previo antes de entrar a LOGO
|
|
||||||
float demo_timer_ = 0.0f; // Contador de tiempo para próxima acción
|
|
||||||
float demo_next_action_time_ = 0.0f; // Tiempo aleatorio hasta próxima acción (segundos)
|
|
||||||
|
|
||||||
// Sistema de convergencia para LOGO MODE (escala con resolución)
|
|
||||||
float shape_convergence_ = 0.0f; // % de pelotas cerca del objetivo (0.0-1.0)
|
|
||||||
float logo_convergence_threshold_ = 0.90f; // Threshold aleatorio (75-100%)
|
|
||||||
float logo_min_time_ = 3.0f; // Tiempo mínimo escalado con resolución
|
|
||||||
float logo_max_time_ = 5.0f; // Tiempo máximo escalado (backup)
|
|
||||||
|
|
||||||
// Sistema de espera de flips en LOGO MODE (camino alternativo)
|
|
||||||
bool logo_waiting_for_flip_ = false; // true si eligió el camino "esperar flip"
|
|
||||||
int logo_target_flip_number_ = 0; // En qué flip actuar (1, 2 o 3)
|
|
||||||
float logo_target_flip_percentage_ = 0.0f; // % de flip a esperar (0.2-0.8)
|
|
||||||
int logo_current_flip_count_ = 0; // Flips observados hasta ahora
|
|
||||||
|
|
||||||
// Estado previo antes de entrar a Logo Mode (para restaurar al salir)
|
|
||||||
int logo_previous_theme_ = 0; // Índice de tema (0-9)
|
|
||||||
size_t logo_previous_texture_index_ = 0;
|
|
||||||
float logo_previous_shape_scale_ = 1.0f;
|
|
||||||
|
|
||||||
// Batch rendering
|
|
||||||
std::vector<SDL_Vertex> batch_vertices_;
|
|
||||||
std::vector<int> batch_indices_;
|
|
||||||
|
|
||||||
// Métodos principales del loop
|
|
||||||
void calculateDeltaTime();
|
|
||||||
void update();
|
|
||||||
void handleEvents();
|
|
||||||
void render();
|
|
||||||
|
|
||||||
// Métodos auxiliares
|
|
||||||
void initBalls(int value);
|
|
||||||
void setText();
|
|
||||||
void pushBallsAwayFromGravity();
|
|
||||||
void switchBallsGravity();
|
|
||||||
void enableBallsGravityIfDisabled();
|
|
||||||
void forceBallsGravityOn();
|
|
||||||
void forceBallsGravityOff();
|
|
||||||
void changeGravityDirection(GravityDirection direction);
|
|
||||||
void toggleVSync();
|
|
||||||
void toggleFullscreen();
|
|
||||||
void toggleRealFullscreen();
|
|
||||||
void toggleIntegerScaling();
|
|
||||||
std::string gravityDirectionToString(GravityDirection direction) const;
|
|
||||||
|
|
||||||
// Sistema de gestión de estados (MANUAL/DEMO/DEMO_LITE/LOGO)
|
|
||||||
void setState(AppMode new_mode); // Cambiar modo de aplicación (mutuamente excluyente)
|
|
||||||
|
|
||||||
// Sistema de Modo DEMO
|
|
||||||
void updateDemoMode();
|
|
||||||
void performDemoAction(bool is_lite);
|
|
||||||
void randomizeOnDemoStart(bool is_lite);
|
|
||||||
void toggleGravityOnOff();
|
|
||||||
|
|
||||||
// Sistema de Modo Logo (easter egg)
|
|
||||||
void toggleLogoMode(); // Activar/desactivar modo logo manual (tecla K)
|
|
||||||
void enterLogoMode(bool from_demo = false); // Entrar al modo logo (manual o automático)
|
|
||||||
void exitLogoMode(bool return_to_demo = false); // Salir del modo logo
|
|
||||||
|
|
||||||
// Sistema de cambio de sprites dinámico
|
|
||||||
void switchTexture(); // Cambia a siguiente textura disponible
|
|
||||||
void updateBallSizes(int old_size, int new_size); // Ajusta posiciones al cambiar tamaño
|
|
||||||
|
|
||||||
// Sistema de zoom dinámico
|
|
||||||
int calculateMaxWindowZoom() const;
|
|
||||||
void setWindowZoom(int new_zoom);
|
|
||||||
void zoomIn();
|
|
||||||
void zoomOut();
|
|
||||||
|
|
||||||
// Rendering
|
|
||||||
void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f);
|
|
||||||
|
|
||||||
// Sistema de Figuras 3D
|
|
||||||
void toggleShapeMode(bool force_gravity_on_exit = true); // Toggle PHYSICS ↔ última figura (tecla F)
|
|
||||||
void activateShape(ShapeType type); // Activar figura específica (teclas Q/W/E/R/Y/U/I)
|
|
||||||
void updateShape(); // Actualizar figura activa
|
|
||||||
void generateShape(); // Generar puntos de figura activa
|
|
||||||
void clampShapeScale(); // Limitar escala para evitar clipping
|
|
||||||
};
|
|
||||||
266
source/engine.hpp
Normal file
266
source/engine.hpp
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL_events.h> // for SDL_Event
|
||||||
|
#include <SDL3/SDL_render.h> // for SDL_Renderer
|
||||||
|
#include <SDL3/SDL_stdinc.h> // for Uint64
|
||||||
|
#include <SDL3/SDL_video.h> // for SDL_Window
|
||||||
|
|
||||||
|
#include <array> // for array
|
||||||
|
#include <memory> // for unique_ptr, shared_ptr
|
||||||
|
#include <string> // for string
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "app_logo.hpp" // for AppLogo
|
||||||
|
#include "ball.hpp" // for Ball
|
||||||
|
#include "boids_mgr/boid_manager.hpp" // for BoidManager
|
||||||
|
#include "defines.hpp" // for GravityDirection, ColorTheme, ShapeType
|
||||||
|
#include "external/texture.hpp" // for Texture
|
||||||
|
#include "input/input_handler.hpp" // for InputHandler
|
||||||
|
#include "scene/scene_manager.hpp" // for SceneManager
|
||||||
|
#include "shapes/shape.hpp" // for Shape (interfaz polimórfica)
|
||||||
|
#include "shapes_mgr/shape_manager.hpp" // for ShapeManager
|
||||||
|
#include "state/state_manager.hpp" // for StateManager
|
||||||
|
#include "theme_manager.hpp" // for ThemeManager
|
||||||
|
#include "ui/ui_manager.hpp" // for UIManager
|
||||||
|
|
||||||
|
class Engine {
|
||||||
|
public:
|
||||||
|
// Interfaz pública principal
|
||||||
|
bool initialize(int width = 0, int height = 0, int zoom = 0, bool fullscreen = false, AppMode initial_mode = AppMode::SANDBOX);
|
||||||
|
void run();
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
// === Métodos públicos para InputHandler ===
|
||||||
|
|
||||||
|
// Gravedad y física
|
||||||
|
void pushBallsAwayFromGravity();
|
||||||
|
void handleGravityToggle();
|
||||||
|
void handleGravityDirectionChange(GravityDirection direction, const char* notification_text);
|
||||||
|
|
||||||
|
// Display y depuración
|
||||||
|
void toggleVSync();
|
||||||
|
void toggleDebug();
|
||||||
|
void toggleHelp();
|
||||||
|
|
||||||
|
// Figuras 3D
|
||||||
|
void toggleShapeMode();
|
||||||
|
void activateShape(ShapeType type, const char* notification_text);
|
||||||
|
void handleShapeScaleChange(bool increase);
|
||||||
|
void resetShapeScale();
|
||||||
|
void toggleDepthZoom();
|
||||||
|
|
||||||
|
// Boids (comportamiento de enjambre)
|
||||||
|
void toggleBoidsMode(bool force_gravity_on = true);
|
||||||
|
|
||||||
|
// Temas de colores
|
||||||
|
void cycleTheme(bool forward);
|
||||||
|
void switchThemeByNumpad(int numpad_key);
|
||||||
|
void toggleThemePage();
|
||||||
|
void pauseDynamicTheme();
|
||||||
|
|
||||||
|
// Sprites/Texturas
|
||||||
|
void switchTexture();
|
||||||
|
|
||||||
|
// Escenarios (número de pelotas)
|
||||||
|
void changeScenario(int scenario_id, const char* notification_text);
|
||||||
|
|
||||||
|
// Zoom y fullscreen
|
||||||
|
void handleZoomIn();
|
||||||
|
void handleZoomOut();
|
||||||
|
void toggleFullscreen();
|
||||||
|
void toggleRealFullscreen();
|
||||||
|
void toggleIntegerScaling();
|
||||||
|
|
||||||
|
// Modo kiosko
|
||||||
|
void setKioskMode(bool enabled) { kiosk_mode_ = enabled; }
|
||||||
|
bool isKioskMode() const { return kiosk_mode_; }
|
||||||
|
|
||||||
|
// Escenario custom (tecla 9, --custom-balls)
|
||||||
|
void setCustomScenario(int balls);
|
||||||
|
bool isCustomScenarioEnabled() const { return custom_scenario_enabled_; }
|
||||||
|
bool isCustomAutoAvailable() const { return custom_auto_available_; }
|
||||||
|
int getCustomScenarioBalls() const { return custom_scenario_balls_; }
|
||||||
|
|
||||||
|
// Control manual del benchmark (--skip-benchmark, --max-balls)
|
||||||
|
void setSkipBenchmark();
|
||||||
|
void setMaxBallsOverride(int n);
|
||||||
|
|
||||||
|
// Notificaciones (público para InputHandler)
|
||||||
|
void showNotificationForAction(const std::string& text);
|
||||||
|
|
||||||
|
// Modos de aplicación (DEMO/LOGO)
|
||||||
|
void toggleDemoMode();
|
||||||
|
void toggleDemoLiteMode();
|
||||||
|
void toggleLogoMode();
|
||||||
|
|
||||||
|
// === Métodos públicos para StateManager (callbacks) ===
|
||||||
|
// NOTA: StateManager coordina estados, Engine proporciona implementación
|
||||||
|
// Estos callbacks permiten que StateManager ejecute acciones complejas que
|
||||||
|
// requieren acceso a múltiples componentes (SceneManager, ThemeManager, ShapeManager, etc.)
|
||||||
|
// Este enfoque es pragmático y mantiene la separación de responsabilidades limpia
|
||||||
|
void performLogoAction(bool logo_waiting_for_flip);
|
||||||
|
void executeDemoAction(bool is_lite);
|
||||||
|
void executeRandomizeOnDemoStart(bool is_lite);
|
||||||
|
void executeToggleGravityOnOff();
|
||||||
|
void executeEnterLogoMode(size_t ball_count);
|
||||||
|
void executeExitLogoMode();
|
||||||
|
|
||||||
|
// === Getters públicos para UIManager (Debug HUD) ===
|
||||||
|
bool getVSyncEnabled() const { return vsync_enabled_; }
|
||||||
|
bool getFullscreenEnabled() const { return fullscreen_enabled_; }
|
||||||
|
bool getRealFullscreenEnabled() const { return real_fullscreen_enabled_; }
|
||||||
|
ScalingMode getCurrentScalingMode() const { return current_scaling_mode_; }
|
||||||
|
int getCurrentScreenWidth() const { return current_screen_width_; }
|
||||||
|
int getCurrentScreenHeight() const { return current_screen_height_; }
|
||||||
|
std::string getCurrentTextureName() const {
|
||||||
|
if (texture_names_.empty()) return "";
|
||||||
|
return texture_names_[current_texture_index_];
|
||||||
|
}
|
||||||
|
int getBaseScreenWidth() const { return base_screen_width_; }
|
||||||
|
int getBaseScreenHeight() const { return base_screen_height_; }
|
||||||
|
int getMaxAutoScenario() const { return max_auto_scenario_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// === Componentes del sistema (Composición) ===
|
||||||
|
std::unique_ptr<InputHandler> input_handler_; // Manejo de entradas SDL
|
||||||
|
std::unique_ptr<SceneManager> scene_manager_; // Gestión de bolas y física
|
||||||
|
std::unique_ptr<ShapeManager> shape_manager_; // Gestión de figuras 3D
|
||||||
|
std::unique_ptr<BoidManager> boid_manager_; // Gestión de comportamiento boids
|
||||||
|
std::unique_ptr<StateManager> state_manager_; // Gestión de estados (DEMO/LOGO)
|
||||||
|
std::unique_ptr<UIManager> ui_manager_; // Gestión de UI (HUD, FPS, notificaciones)
|
||||||
|
std::unique_ptr<AppLogo> app_logo_; // Gestión de logo periódico en pantalla
|
||||||
|
|
||||||
|
// Recursos SDL
|
||||||
|
SDL_Window* window_ = nullptr;
|
||||||
|
SDL_Renderer* renderer_ = nullptr;
|
||||||
|
std::shared_ptr<Texture> texture_ = nullptr; // Textura activa actual
|
||||||
|
std::vector<std::shared_ptr<Texture>> textures_; // Todas las texturas disponibles
|
||||||
|
std::vector<std::string> texture_names_; // Nombres de texturas (sin extensión)
|
||||||
|
size_t current_texture_index_ = 0; // Índice de textura activa
|
||||||
|
int current_ball_size_ = 10; // Tamaño actual de pelotas (dinámico, se actualiza desde texture)
|
||||||
|
|
||||||
|
// Estado del simulador
|
||||||
|
bool should_exit_ = false;
|
||||||
|
|
||||||
|
// Sistema de timing
|
||||||
|
Uint64 last_frame_time_ = 0;
|
||||||
|
float delta_time_ = 0.0f;
|
||||||
|
|
||||||
|
// Sistema de zoom dinámico
|
||||||
|
int current_window_zoom_ = DEFAULT_WINDOW_ZOOM;
|
||||||
|
|
||||||
|
// V-Sync
|
||||||
|
bool vsync_enabled_ = true;
|
||||||
|
bool fullscreen_enabled_ = false;
|
||||||
|
bool real_fullscreen_enabled_ = false;
|
||||||
|
bool kiosk_mode_ = false;
|
||||||
|
ScalingMode current_scaling_mode_ = ScalingMode::INTEGER; // Modo de escalado actual (F5)
|
||||||
|
|
||||||
|
// Resolución base (configurada por CLI o default)
|
||||||
|
int base_screen_width_ = DEFAULT_SCREEN_WIDTH;
|
||||||
|
int base_screen_height_ = DEFAULT_SCREEN_HEIGHT;
|
||||||
|
|
||||||
|
// Resolución dinámica actual (cambia en fullscreen real)
|
||||||
|
int current_screen_width_ = DEFAULT_SCREEN_WIDTH;
|
||||||
|
int current_screen_height_ = DEFAULT_SCREEN_HEIGHT;
|
||||||
|
|
||||||
|
// Resolución física real de ventana/pantalla (para texto absoluto)
|
||||||
|
int physical_window_width_ = DEFAULT_SCREEN_WIDTH;
|
||||||
|
int physical_window_height_ = DEFAULT_SCREEN_HEIGHT;
|
||||||
|
|
||||||
|
// Sistema de temas (delegado a ThemeManager)
|
||||||
|
std::unique_ptr<ThemeManager> theme_manager_;
|
||||||
|
int theme_page_ = 0; // Página actual de temas (0 o 1) para acceso por Numpad
|
||||||
|
|
||||||
|
// Sistema de Figuras 3D (polimórfico)
|
||||||
|
// NOTA: Engine mantiene implementación de figuras usada por callbacks DEMO/LOGO
|
||||||
|
// ShapeManager tiene implementación paralela para controles manuales del usuario
|
||||||
|
SimulationMode current_mode_ = SimulationMode::PHYSICS;
|
||||||
|
ShapeType current_shape_type_ = ShapeType::SPHERE; // Tipo de figura actual
|
||||||
|
ShapeType last_shape_type_ = ShapeType::SPHERE; // Última figura para toggle F
|
||||||
|
std::unique_ptr<Shape> active_shape_; // Puntero polimórfico a figura activa
|
||||||
|
float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-)
|
||||||
|
bool depth_zoom_enabled_ = true; // Zoom por profundidad Z activado
|
||||||
|
|
||||||
|
// Sistema de Modo DEMO (auto-play) y LOGO
|
||||||
|
// NOTA: Engine mantiene estado de implementación para callbacks performLogoAction()
|
||||||
|
// StateManager coordina los triggers y timers, Engine ejecuta las acciones
|
||||||
|
float demo_timer_ = 0.0f; // Contador de tiempo para próxima acción
|
||||||
|
float demo_next_action_time_ = 0.0f; // Tiempo aleatorio hasta próxima acción (segundos)
|
||||||
|
int max_auto_scenario_ = 5; // Índice máximo en modos auto (default conservador: 5000 bolas)
|
||||||
|
|
||||||
|
// Escenario custom (--custom-balls)
|
||||||
|
int custom_scenario_balls_ = 0;
|
||||||
|
bool custom_scenario_enabled_ = false;
|
||||||
|
bool custom_auto_available_ = false;
|
||||||
|
bool skip_benchmark_ = false;
|
||||||
|
|
||||||
|
// Sistema de convergencia para LOGO MODE (escala con resolución)
|
||||||
|
// Usado por performLogoAction() para detectar cuando las bolas forman el logo
|
||||||
|
float shape_convergence_ = 0.0f; // % de pelotas cerca del objetivo (0.0-1.0)
|
||||||
|
float logo_convergence_threshold_ = 0.90f; // Threshold aleatorio (75-100%)
|
||||||
|
float logo_min_time_ = 3.0f; // Tiempo mínimo escalado con resolución
|
||||||
|
float logo_max_time_ = 5.0f; // Tiempo máximo escalado (backup)
|
||||||
|
|
||||||
|
// Sistema de espera de flips en LOGO MODE (camino alternativo)
|
||||||
|
// Permite que LOGO espere a que ocurran rotaciones antes de cambiar estado
|
||||||
|
bool logo_waiting_for_flip_ = false; // true si eligió el camino "esperar flip"
|
||||||
|
int logo_target_flip_number_ = 0; // En qué flip actuar (1, 2 o 3)
|
||||||
|
float logo_target_flip_percentage_ = 0.0f; // % de flip a esperar (0.2-0.8)
|
||||||
|
int logo_current_flip_count_ = 0; // Flips observados hasta ahora
|
||||||
|
|
||||||
|
// NOTA: logo_entered_manually_ fue eliminado de Engine (duplicado)
|
||||||
|
// Ahora se obtiene de StateManager con state_manager_->getLogoEnteredManually()
|
||||||
|
// Esto evita desincronización entre Engine y StateManager
|
||||||
|
|
||||||
|
// Estado previo antes de entrar a Logo Mode (para restaurar al salir)
|
||||||
|
// Guardado por executeEnterLogoMode(), restaurado por executeExitLogoMode()
|
||||||
|
int logo_previous_theme_ = 0; // Índice de tema (0-9)
|
||||||
|
size_t logo_previous_texture_index_ = 0;
|
||||||
|
float logo_previous_shape_scale_ = 1.0f;
|
||||||
|
|
||||||
|
// Batch rendering
|
||||||
|
std::vector<SDL_Vertex> batch_vertices_;
|
||||||
|
std::vector<int> batch_indices_;
|
||||||
|
|
||||||
|
// Bucket sort per z-ordering (SHAPE mode)
|
||||||
|
static constexpr int DEPTH_SORT_BUCKETS = 256;
|
||||||
|
std::array<std::vector<size_t>, DEPTH_SORT_BUCKETS> depth_buckets_;
|
||||||
|
|
||||||
|
// Configuración del sistema de texto (constantes configurables)
|
||||||
|
static constexpr const char* TEXT_FONT_PATH = "data/fonts/determination.ttf";
|
||||||
|
static constexpr int TEXT_BASE_SIZE = 24; // Tamaño base para 240p
|
||||||
|
static constexpr bool TEXT_ANTIALIASING = true; // true = suavizado, false = píxeles nítidos
|
||||||
|
|
||||||
|
// Métodos principales del loop
|
||||||
|
void calculateDeltaTime();
|
||||||
|
void update();
|
||||||
|
void render();
|
||||||
|
|
||||||
|
// Benchmark de rendimiento (determina max_auto_scenario_ al inicio)
|
||||||
|
void runPerformanceBenchmark();
|
||||||
|
|
||||||
|
// Métodos auxiliares privados (llamados por la interfaz pública)
|
||||||
|
|
||||||
|
// Sistema de cambio de sprites dinámico - Métodos privados
|
||||||
|
void switchTextureInternal(bool show_notification); // Implementación interna del cambio de textura
|
||||||
|
|
||||||
|
// Sistema de zoom dinámico - Métodos privados
|
||||||
|
int calculateMaxWindowZoom() const;
|
||||||
|
void setWindowZoom(int new_zoom);
|
||||||
|
void zoomIn();
|
||||||
|
void zoomOut();
|
||||||
|
void updatePhysicalWindowSize(); // Actualizar tamaño físico real de ventana
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f);
|
||||||
|
|
||||||
|
// Sistema de Figuras 3D - Métodos privados
|
||||||
|
// NOTA FASE 7: Métodos DUPLICADOS con ShapeManager (Engine mantiene implementación para DEMO/LOGO)
|
||||||
|
// TODO FASE 8: Convertir en wrappers puros cuando migremos DEMO/LOGO
|
||||||
|
void toggleShapeModeInternal(bool force_gravity_on_exit = true); // Implementación interna del toggle
|
||||||
|
void activateShapeInternal(ShapeType type); // Implementación interna de activación
|
||||||
|
void updateShape(); // Actualizar figura activa
|
||||||
|
void generateShape(); // Generar puntos de figura activa
|
||||||
|
void clampShapeScale(); // Limitar escala para evitar clipping
|
||||||
|
};
|
||||||
78
source/external/dbgtxt.h
vendored
78
source/external/dbgtxt.h
vendored
@@ -1,78 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
SDL_Texture* dbg_tex = nullptr;
|
|
||||||
SDL_Renderer* dbg_ren = nullptr;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
inline void dbg_init(SDL_Renderer* renderer) {
|
|
||||||
dbg_ren = renderer;
|
|
||||||
Uint8 font[448] = {0x42, 0x4D, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x18, 0xF3, 0x83, 0x83, 0xCF, 0x83, 0x87, 0x00, 0x00, 0xF3, 0x39, 0x39, 0xCF, 0x79, 0xF3, 0x00, 0x00, 0x01, 0xF9, 0x39, 0xCF, 0x61, 0xF9, 0x00, 0x00, 0x33, 0xF9, 0x03, 0xE7, 0x87, 0x81, 0x00, 0x00, 0x93, 0x03, 0x3F, 0xF3, 0x1B, 0x39, 0x00, 0x00, 0xC3, 0x3F, 0x9F, 0x39, 0x3B, 0x39, 0x00, 0x41, 0xE3, 0x03, 0xC3, 0x01, 0x87, 0x83, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE7, 0x01, 0xC7, 0x81, 0x01, 0x83, 0x00, 0x00, 0xE7, 0x1F, 0x9B, 0xE7, 0x1F, 0x39, 0x00, 0x00, 0xE7, 0x8F, 0x39, 0xE7, 0x87, 0xF9, 0x00, 0x00, 0xC3, 0xC7, 0x39, 0xE7, 0xC3, 0xC3, 0x00, 0x00, 0x99, 0xE3, 0x39, 0xE7, 0xF1, 0xE7, 0x00, 0x00, 0x99, 0xF1, 0xB3, 0xC7, 0x39, 0xF3, 0x00, 0x00, 0x99, 0x01, 0xC7, 0xE7, 0x83, 0x81, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x83, 0xE7, 0x83, 0xEF, 0x39, 0x39, 0x00, 0x00, 0x39, 0xE7, 0x39, 0xC7, 0x11, 0x11, 0x00, 0x00, 0xF9, 0xE7, 0x39, 0x83, 0x01, 0x83, 0x00, 0x00, 0x83, 0xE7, 0x39, 0x11, 0x01, 0xC7, 0x00, 0x00, 0x3F, 0xE7, 0x39, 0x39, 0x29, 0x83, 0x00, 0x00, 0x33, 0xE7, 0x39, 0x39, 0x39, 0x11, 0x00, 0x00, 0x87, 0x81, 0x39, 0x39, 0x39, 0x39, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x39, 0x39, 0x83, 0x3F, 0x85, 0x31, 0x00, 0x00, 0x39, 0x31, 0x39, 0x3F, 0x33, 0x23, 0x00, 0x00, 0x29, 0x21, 0x39, 0x03, 0x21, 0x07, 0x00, 0x00, 0x01, 0x01, 0x39, 0x39, 0x39, 0x31, 0x00, 0x00, 0x01, 0x09, 0x39, 0x39, 0x39, 0x39, 0x00, 0x00, 0x11, 0x19, 0x39, 0x39, 0x39, 0x39, 0x00, 0x00, 0x39, 0x39, 0x83, 0x03, 0x83, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xC1, 0x39, 0x81, 0x83, 0x31, 0x01, 0x00, 0x00, 0x99, 0x39, 0xE7, 0x39, 0x23, 0x3F, 0x00, 0x00, 0x39, 0x39, 0xE7, 0xF9, 0x07, 0x3F, 0x00, 0x00, 0x31, 0x01, 0xE7, 0xF9, 0x0F, 0x3F, 0x00, 0x00, 0x3F, 0x39, 0xE7, 0xF9, 0x27, 0x3F, 0x00, 0x00, 0x9F, 0x39, 0xE7, 0xF9, 0x33, 0x3F, 0x00, 0x00, 0xC1, 0x39, 0x81, 0xF9, 0x39, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x39, 0x03, 0xC3, 0x07, 0x01, 0x3F, 0x00, 0x00, 0x39, 0x39, 0x99, 0x33, 0x3F, 0x3F, 0x00, 0x00, 0x01, 0x39, 0x3F, 0x39, 0x3F, 0x3F, 0x00, 0x00, 0x39, 0x03, 0x3F, 0x39, 0x03, 0x03, 0x00, 0x00, 0x39, 0x39, 0x3F, 0x39, 0x3F, 0x3F, 0x00, 0x00, 0x93, 0x39, 0x99, 0x33, 0x3F, 0x3F, 0x00, 0x00, 0xC7, 0x03, 0xC3, 0x07, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
// Cargar surface del bitmap font
|
|
||||||
SDL_Surface* font_surface = SDL_LoadBMP_IO(SDL_IOFromMem(font, 448), 1);
|
|
||||||
if (font_surface != nullptr) {
|
|
||||||
// Crear una nueva surface de 32 bits con canal alpha
|
|
||||||
SDL_Surface* rgba_surface = SDL_CreateSurface(font_surface->w, font_surface->h, SDL_PIXELFORMAT_RGBA8888);
|
|
||||||
if (rgba_surface != nullptr) {
|
|
||||||
// Obtener píxeles de ambas surfaces
|
|
||||||
Uint8* src_pixels = (Uint8*)font_surface->pixels;
|
|
||||||
Uint32* dst_pixels = (Uint32*)rgba_surface->pixels;
|
|
||||||
|
|
||||||
int width = font_surface->w;
|
|
||||||
int height = font_surface->h;
|
|
||||||
|
|
||||||
// Procesar cada píxel
|
|
||||||
for (int y = 0; y < height; y++) {
|
|
||||||
for (int x = 0; x < width; x++) {
|
|
||||||
int byte_index = y * font_surface->pitch + (x / 8);
|
|
||||||
int bit_index = 7 - (x % 8);
|
|
||||||
|
|
||||||
// Extraer bit del bitmap monocromo
|
|
||||||
bool is_white = (src_pixels[byte_index] >> bit_index) & 1;
|
|
||||||
|
|
||||||
if (is_white) // Fondo blanco original -> transparente
|
|
||||||
{
|
|
||||||
dst_pixels[y * width + x] = 0x00000000; // Transparente
|
|
||||||
} else // Texto negro original -> blanco opaco
|
|
||||||
{
|
|
||||||
dst_pixels[y * width + x] = 0xFFFFFFFF; // Blanco opaco
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg_tex = SDL_CreateTextureFromSurface(dbg_ren, rgba_surface);
|
|
||||||
SDL_DestroySurface(rgba_surface);
|
|
||||||
}
|
|
||||||
SDL_DestroySurface(font_surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configurar filtro nearest neighbor para píxel perfect del texto
|
|
||||||
if (dbg_tex != nullptr) {
|
|
||||||
SDL_SetTextureScaleMode(dbg_tex, SDL_SCALEMODE_NEAREST);
|
|
||||||
// Configurar blend mode para transparencia normal
|
|
||||||
SDL_SetTextureBlendMode(dbg_tex, SDL_BLENDMODE_BLEND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void dbg_print(int x, int y, const char* text, Uint8 r, Uint8 g, Uint8 b) {
|
|
||||||
int cc = 0;
|
|
||||||
SDL_SetTextureColorMod(dbg_tex, r, g, b);
|
|
||||||
SDL_FRect src = {0, 0, 8, 8};
|
|
||||||
SDL_FRect dst = {static_cast<float>(x), static_cast<float>(y), 8, 8};
|
|
||||||
while (text[cc] != 0) {
|
|
||||||
if (text[cc] != 32) {
|
|
||||||
if (text[cc] >= 65) {
|
|
||||||
src.x = ((text[cc] - 65) % 6) * 8;
|
|
||||||
src.y = ((text[cc] - 65) / 6) * 8;
|
|
||||||
} else {
|
|
||||||
src.x = ((text[cc] - 22) % 6) * 8;
|
|
||||||
src.y = ((text[cc] - 22) / 6) * 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_RenderTexture(dbg_ren, dbg_tex, &src, &dst);
|
|
||||||
}
|
|
||||||
cc++;
|
|
||||||
dst.x += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
source/external/mouse.cpp
vendored
2
source/external/mouse.cpp
vendored
@@ -1,4 +1,4 @@
|
|||||||
#include "mouse.h"
|
#include "mouse.hpp"
|
||||||
|
|
||||||
#include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_HideCursor, SDL_ShowCursor
|
#include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_HideCursor, SDL_ShowCursor
|
||||||
|
|
||||||
|
|||||||
4
source/external/sprite.cpp
vendored
4
source/external/sprite.cpp
vendored
@@ -1,6 +1,6 @@
|
|||||||
#include "sprite.h"
|
#include "sprite.hpp"
|
||||||
|
|
||||||
#include "texture.h" // for Texture
|
#include "texture.hpp" // for Texture
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Sprite::Sprite(std::shared_ptr<Texture> texture)
|
Sprite::Sprite(std::shared_ptr<Texture> texture)
|
||||||
|
|||||||
10630
source/external/stb_image_resize2.h
vendored
Normal file
10630
source/external/stb_image_resize2.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
85
source/external/texture.cpp
vendored
85
source/external/texture.cpp
vendored
@@ -1,5 +1,5 @@
|
|||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "texture.h"
|
#include "texture.hpp"
|
||||||
|
|
||||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||||
#include <SDL3/SDL_log.h> // Para SDL_Log
|
#include <SDL3/SDL_log.h> // Para SDL_Log
|
||||||
@@ -12,38 +12,7 @@
|
|||||||
#include <string> // Para operator<<, string
|
#include <string> // Para operator<<, string
|
||||||
|
|
||||||
#include "stb_image.h" // Para stbi_failure_reason, stbi_image_free
|
#include "stb_image.h" // Para stbi_failure_reason, stbi_image_free
|
||||||
#include "../resource_pack.h" // Sistema de empaquetado de recursos
|
#include "resource_manager.hpp" // Sistema de empaquetado de recursos centralizado
|
||||||
|
|
||||||
// Instancia global de ResourcePack (se inicializa al primer uso)
|
|
||||||
static ResourcePack* g_resourcePack = nullptr;
|
|
||||||
|
|
||||||
// Inicializar el sistema de recursos (llamar desde main antes de cargar texturas)
|
|
||||||
void Texture::initResourceSystem(const std::string& packFilePath) {
|
|
||||||
if (g_resourcePack == nullptr) {
|
|
||||||
g_resourcePack = new ResourcePack();
|
|
||||||
if (!g_resourcePack->loadPack(packFilePath)) {
|
|
||||||
// Si falla, borrar instancia (usará fallback a disco)
|
|
||||||
delete g_resourcePack;
|
|
||||||
g_resourcePack = nullptr;
|
|
||||||
std::cout << "resources.pack no encontrado - usando carpeta data/" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "resources.pack cargado (" << g_resourcePack->getResourceCount() << " recursos)" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener lista de recursos disponibles en el pack
|
|
||||||
std::vector<std::string> Texture::getPackResourceList() {
|
|
||||||
if (g_resourcePack != nullptr) {
|
|
||||||
return g_resourcePack->getResourceList();
|
|
||||||
}
|
|
||||||
return std::vector<std::string>(); // Vacío si no hay pack
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verificar si el pack está cargado
|
|
||||||
bool Texture::isPackLoaded() {
|
|
||||||
return g_resourcePack != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture::Texture(SDL_Renderer *renderer)
|
Texture::Texture(SDL_Renderer *renderer)
|
||||||
: renderer_(renderer),
|
: renderer_(renderer),
|
||||||
@@ -70,30 +39,29 @@ bool Texture::loadFromFile(const std::string &file_path) {
|
|||||||
int width, height, orig_format;
|
int width, height, orig_format;
|
||||||
unsigned char *data = nullptr;
|
unsigned char *data = nullptr;
|
||||||
|
|
||||||
// 1. Intentar cargar desde pack (si está inicializado)
|
// 1. Intentar cargar desde ResourceManager (pack o disco)
|
||||||
if (g_resourcePack != nullptr) {
|
unsigned char* resourceData = nullptr;
|
||||||
ResourcePack::ResourceData packData = g_resourcePack->loadResource(file_path);
|
size_t resourceSize = 0;
|
||||||
if (packData.data != nullptr) {
|
|
||||||
// Descodificar imagen desde memoria usando stb_image
|
|
||||||
data = stbi_load_from_memory(packData.data, static_cast<int>(packData.size),
|
|
||||||
&width, &height, &orig_format, req_format);
|
|
||||||
delete[] packData.data; // Liberar buffer temporal del pack
|
|
||||||
|
|
||||||
if (data != nullptr) {
|
if (ResourceManager::loadResource(file_path, resourceData, resourceSize)) {
|
||||||
|
// Descodificar imagen desde memoria usando stb_image
|
||||||
|
data = stbi_load_from_memory(resourceData, static_cast<int>(resourceSize),
|
||||||
|
&width, &height, &orig_format, req_format);
|
||||||
|
delete[] resourceData; // Liberar buffer temporal
|
||||||
|
|
||||||
|
if (data != nullptr) {
|
||||||
|
if (ResourceManager::isPackLoaded()) {
|
||||||
std::cout << "Imagen cargada desde pack: " << filename.c_str() << std::endl;
|
std::cout << "Imagen cargada desde pack: " << filename.c_str() << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Imagen cargada desde disco: " << filename.c_str() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Fallback: cargar desde disco (modo desarrollo)
|
// 2. Si todo falla, error
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format);
|
SDL_Log("Error al cargar la imagen: %s", stbi_failure_reason());
|
||||||
if (data == nullptr) {
|
exit(1);
|
||||||
SDL_Log("Error al cargar la imagen: %s", stbi_failure_reason());
|
|
||||||
exit(1);
|
|
||||||
} else {
|
|
||||||
std::cout << "Imagen cargada desde disco: " << filename.c_str() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pitch;
|
int pitch;
|
||||||
@@ -128,6 +96,9 @@ bool Texture::loadFromFile(const std::string &file_path) {
|
|||||||
|
|
||||||
// Configurar filtro nearest neighbor para píxel perfect
|
// Configurar filtro nearest neighbor para píxel perfect
|
||||||
SDL_SetTextureScaleMode(new_texture, SDL_SCALEMODE_NEAREST);
|
SDL_SetTextureScaleMode(new_texture, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
|
// Habilitar alpha blending para transparencias
|
||||||
|
SDL_SetTextureBlendMode(new_texture, SDL_BLENDMODE_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destruye la superficie cargada
|
// Destruye la superficie cargada
|
||||||
@@ -169,3 +140,17 @@ int Texture::getHeight() {
|
|||||||
void Texture::setColor(int r, int g, int b) {
|
void Texture::setColor(int r, int g, int b) {
|
||||||
SDL_SetTextureColorMod(texture_, r, g, b);
|
SDL_SetTextureColorMod(texture_, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Modula el alpha de la textura
|
||||||
|
void Texture::setAlpha(int alpha) {
|
||||||
|
if (texture_ != nullptr) {
|
||||||
|
SDL_SetTextureAlphaMod(texture_, static_cast<Uint8>(alpha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configurar modo de escalado
|
||||||
|
void Texture::setScaleMode(SDL_ScaleMode mode) {
|
||||||
|
if (texture_ != nullptr) {
|
||||||
|
SDL_SetTextureScaleMode(texture_, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,11 +16,6 @@ class Texture {
|
|||||||
int height_;
|
int height_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Sistema de recursos empaquetados (inicializar desde main)
|
|
||||||
static void initResourceSystem(const std::string& packFilePath);
|
|
||||||
static std::vector<std::string> getPackResourceList();
|
|
||||||
static bool isPackLoaded();
|
|
||||||
|
|
||||||
// Inicializa las variables
|
// Inicializa las variables
|
||||||
explicit Texture(SDL_Renderer *renderer);
|
explicit Texture(SDL_Renderer *renderer);
|
||||||
Texture(SDL_Renderer *renderer, const std::string &file_path);
|
Texture(SDL_Renderer *renderer, const std::string &file_path);
|
||||||
@@ -44,6 +39,12 @@ class Texture {
|
|||||||
// Modula el color de la textura
|
// Modula el color de la textura
|
||||||
void setColor(int r, int g, int b);
|
void setColor(int r, int g, int b);
|
||||||
|
|
||||||
|
// Modula el alpha (transparencia) de la textura
|
||||||
|
void setAlpha(int alpha);
|
||||||
|
|
||||||
|
// Configurar modo de escalado (NEAREST para pixel art, LINEAR para suavizado)
|
||||||
|
void setScaleMode(SDL_ScaleMode mode);
|
||||||
|
|
||||||
// Getter para batch rendering
|
// Getter para batch rendering
|
||||||
SDL_Texture *getSDLTexture() const { return texture_; }
|
SDL_Texture *getSDLTexture() const { return texture_; }
|
||||||
};
|
};
|
||||||
292
source/input/input_handler.cpp
Normal file
292
source/input/input_handler.cpp
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
#include "input_handler.hpp"
|
||||||
|
|
||||||
|
#include <SDL3/SDL_keycode.h> // for SDL_Keycode
|
||||||
|
#include <string> // for std::string, std::to_string
|
||||||
|
|
||||||
|
#include "defines.hpp" // for KIOSK_NOTIFICATION_TEXT
|
||||||
|
#include "engine.hpp" // for Engine
|
||||||
|
#include "external/mouse.hpp" // for Mouse namespace
|
||||||
|
|
||||||
|
bool InputHandler::processEvents(Engine& engine) {
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
// Procesar eventos de ratón (auto-ocultar cursor)
|
||||||
|
Mouse::handleEvent(event);
|
||||||
|
|
||||||
|
// Salir del bucle si se detecta una petición de cierre
|
||||||
|
if (event.type == SDL_EVENT_QUIT) {
|
||||||
|
return true; // Solicitar salida
|
||||||
|
}
|
||||||
|
|
||||||
|
// Procesar eventos de teclado
|
||||||
|
if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) {
|
||||||
|
switch (event.key.key) {
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
if (engine.isKioskMode()) {
|
||||||
|
engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true; // Solicitar salida
|
||||||
|
|
||||||
|
case SDLK_SPACE:
|
||||||
|
engine.pushBallsAwayFromGravity();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_G:
|
||||||
|
engine.handleGravityToggle();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Controles de dirección de gravedad con teclas de cursor
|
||||||
|
case SDLK_UP:
|
||||||
|
engine.handleGravityDirectionChange(GravityDirection::UP, "Gravedad Arriba");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_DOWN:
|
||||||
|
engine.handleGravityDirectionChange(GravityDirection::DOWN, "Gravedad Abajo");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_LEFT:
|
||||||
|
engine.handleGravityDirectionChange(GravityDirection::LEFT, "Gravedad Izquierda");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_RIGHT:
|
||||||
|
engine.handleGravityDirectionChange(GravityDirection::RIGHT, "Gravedad Derecha");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_V:
|
||||||
|
engine.toggleVSync();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_H:
|
||||||
|
engine.toggleHelp(); // Toggle ayuda de teclas
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Física ↔ Última Figura (antes era C)
|
||||||
|
case SDLK_F:
|
||||||
|
engine.toggleShapeMode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Selección directa de figuras 3D
|
||||||
|
case SDLK_Q:
|
||||||
|
engine.activateShape(ShapeType::SPHERE, "Esfera");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_W:
|
||||||
|
engine.activateShape(ShapeType::LISSAJOUS, "Lissajous");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_E:
|
||||||
|
engine.activateShape(ShapeType::HELIX, "Hélice");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_R:
|
||||||
|
engine.activateShape(ShapeType::TORUS, "Toroide");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_T:
|
||||||
|
engine.activateShape(ShapeType::CUBE, "Cubo");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_Y:
|
||||||
|
engine.activateShape(ShapeType::CYLINDER, "Cilindro");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_U:
|
||||||
|
engine.activateShape(ShapeType::ICOSAHEDRON, "Icosaedro");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_I:
|
||||||
|
engine.activateShape(ShapeType::ATOM, "Átomo");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_O:
|
||||||
|
engine.activateShape(ShapeType::PNG_SHAPE, "Forma PNG");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Modo Boids (comportamiento de enjambre)
|
||||||
|
case SDLK_B:
|
||||||
|
engine.toggleBoidsMode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Ciclar temas de color (movido de B a C)
|
||||||
|
case SDLK_C:
|
||||||
|
{
|
||||||
|
// Detectar si Shift está presionado
|
||||||
|
SDL_Keymod modstate = SDL_GetModState();
|
||||||
|
if (modstate & SDL_KMOD_SHIFT) {
|
||||||
|
// Shift+C: Ciclar hacia atrás (tema anterior)
|
||||||
|
engine.cycleTheme(false);
|
||||||
|
} else {
|
||||||
|
// C solo: Ciclar hacia adelante (tema siguiente)
|
||||||
|
engine.cycleTheme(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Temas de colores con teclado numérico (con transición suave)
|
||||||
|
case SDLK_KP_1:
|
||||||
|
engine.switchThemeByNumpad(1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_2:
|
||||||
|
engine.switchThemeByNumpad(2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_3:
|
||||||
|
engine.switchThemeByNumpad(3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_4:
|
||||||
|
engine.switchThemeByNumpad(4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_5:
|
||||||
|
engine.switchThemeByNumpad(5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_6:
|
||||||
|
engine.switchThemeByNumpad(6);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_7:
|
||||||
|
engine.switchThemeByNumpad(7);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_8:
|
||||||
|
engine.switchThemeByNumpad(8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_9:
|
||||||
|
engine.switchThemeByNumpad(9);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_0:
|
||||||
|
engine.switchThemeByNumpad(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle de página de temas (Numpad Enter)
|
||||||
|
case SDLK_KP_ENTER:
|
||||||
|
engine.toggleThemePage();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Cambio de sprite/textura dinámico
|
||||||
|
case SDLK_N:
|
||||||
|
engine.switchTexture();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Control de escala de figura (solo en modo SHAPE)
|
||||||
|
case SDLK_KP_PLUS:
|
||||||
|
engine.handleShapeScaleChange(true); // Aumentar
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_MINUS:
|
||||||
|
engine.handleShapeScaleChange(false); // Disminuir
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_MULTIPLY:
|
||||||
|
engine.resetShapeScale();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_KP_DIVIDE:
|
||||||
|
engine.toggleDepthZoom();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Cambio de número de pelotas (escenarios 1-8)
|
||||||
|
case SDLK_1:
|
||||||
|
engine.changeScenario(0, "10 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_2:
|
||||||
|
engine.changeScenario(1, "50 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_3:
|
||||||
|
engine.changeScenario(2, "100 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_4:
|
||||||
|
engine.changeScenario(3, "500 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_5:
|
||||||
|
engine.changeScenario(4, "1,000 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_6:
|
||||||
|
engine.changeScenario(5, "5,000 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_7:
|
||||||
|
engine.changeScenario(6, "10,000 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_8:
|
||||||
|
engine.changeScenario(7, "50,000 Pelotas");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_9:
|
||||||
|
if (engine.isCustomScenarioEnabled()) {
|
||||||
|
std::string custom_notif = std::to_string(engine.getCustomScenarioBalls()) + " Pelotas";
|
||||||
|
engine.changeScenario(CUSTOM_SCENARIO_IDX, custom_notif.c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Controles de zoom dinámico (solo si no estamos en fullscreen)
|
||||||
|
case SDLK_F1:
|
||||||
|
if (engine.isKioskMode()) engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT);
|
||||||
|
else engine.handleZoomOut();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_F2:
|
||||||
|
if (engine.isKioskMode()) engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT);
|
||||||
|
else engine.handleZoomIn();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Control de pantalla completa
|
||||||
|
case SDLK_F3:
|
||||||
|
if (engine.isKioskMode()) engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT);
|
||||||
|
else engine.toggleFullscreen();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Modo real fullscreen (cambia resolución interna)
|
||||||
|
case SDLK_F4:
|
||||||
|
if (engine.isKioskMode()) engine.showNotificationForAction(KIOSK_NOTIFICATION_TEXT);
|
||||||
|
else engine.toggleRealFullscreen();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle escalado entero/estirado (solo en fullscreen F3)
|
||||||
|
case SDLK_F5:
|
||||||
|
engine.toggleIntegerScaling();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Modo DEMO COMPLETO (auto-play) o Pausar tema dinámico (Shift+D)
|
||||||
|
case SDLK_D:
|
||||||
|
// Shift+D = Pausar tema dinámico
|
||||||
|
if (event.key.mod & SDL_KMOD_SHIFT) {
|
||||||
|
engine.pauseDynamicTheme();
|
||||||
|
} else {
|
||||||
|
// D sin Shift = Toggle DEMO ↔ SANDBOX
|
||||||
|
engine.toggleDemoMode();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Modo DEMO LITE (solo física/figuras)
|
||||||
|
case SDLK_L:
|
||||||
|
engine.toggleDemoLiteMode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Modo LOGO (easter egg - marca de agua)
|
||||||
|
case SDLK_K:
|
||||||
|
engine.toggleLogoMode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Toggle Debug Display (movido de H a F12)
|
||||||
|
case SDLK_F12:
|
||||||
|
engine.toggleDebug();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // No se solicitó salida
|
||||||
|
}
|
||||||
32
source/input/input_handler.hpp
Normal file
32
source/input/input_handler.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL_events.h> // for SDL_Event
|
||||||
|
|
||||||
|
// Forward declaration para evitar dependencia circular
|
||||||
|
class Engine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class InputHandler
|
||||||
|
* @brief Procesa eventos de entrada (teclado, ratón, ventana) y los traduce a acciones del Engine
|
||||||
|
*
|
||||||
|
* Responsabilidad única: Manejo de input SDL y traducción a comandos de alto nivel
|
||||||
|
*
|
||||||
|
* Características:
|
||||||
|
* - Procesa todos los eventos SDL (teclado, ratón, quit)
|
||||||
|
* - Traduce inputs a llamadas de métodos del Engine
|
||||||
|
* - Mantiene el Engine desacoplado de la lógica de input SDL
|
||||||
|
* - Soporta todos los controles del proyecto (gravedad, figuras, temas, zoom, fullscreen)
|
||||||
|
*/
|
||||||
|
class InputHandler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Procesa todos los eventos SDL pendientes
|
||||||
|
* @param engine Referencia al engine para ejecutar acciones
|
||||||
|
* @return true si se debe salir de la aplicación (ESC o cerrar ventana), false en caso contrario
|
||||||
|
*/
|
||||||
|
bool processEvents(Engine& engine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Sin estado interno por ahora - el InputHandler es stateless
|
||||||
|
// Todos los estados se delegan al Engine
|
||||||
|
};
|
||||||
157
source/logo_scaler.cpp
Normal file
157
source/logo_scaler.cpp
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||||
|
#include "logo_scaler.hpp"
|
||||||
|
|
||||||
|
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||||
|
#include <SDL3/SDL_log.h> // Para SDL_Log
|
||||||
|
#include <SDL3/SDL_pixels.h> // Para SDL_PixelFormat
|
||||||
|
#include <SDL3/SDL_render.h> // Para SDL_CreateTexture
|
||||||
|
#include <SDL3/SDL_surface.h> // Para SDL_CreateSurfaceFrom
|
||||||
|
#include <SDL3/SDL_video.h> // Para SDL_GetDisplays
|
||||||
|
|
||||||
|
#include <cstdlib> // Para free()
|
||||||
|
#include <iostream> // Para std::cout
|
||||||
|
|
||||||
|
#include "external/stb_image.h" // Para stbi_load, stbi_image_free
|
||||||
|
#include "external/stb_image_resize2.h" // Para stbir_resize_uint8_srgb
|
||||||
|
#include "resource_manager.hpp" // Para cargar desde pack
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Detectar resolución nativa del monitor principal
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
bool LogoScaler::detectNativeResolution(int& native_width, int& native_height) {
|
||||||
|
int num_displays = 0;
|
||||||
|
SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
|
||||||
|
|
||||||
|
if (displays == nullptr || num_displays == 0) {
|
||||||
|
SDL_Log("Error al obtener displays: %s", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener resolución del display principal (displays[0])
|
||||||
|
const auto* dm = SDL_GetCurrentDisplayMode(displays[0]);
|
||||||
|
if (dm == nullptr) {
|
||||||
|
SDL_Log("Error al obtener modo del display: %s", SDL_GetError());
|
||||||
|
SDL_free(displays);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
native_width = dm->w;
|
||||||
|
native_height = dm->h;
|
||||||
|
|
||||||
|
SDL_free(displays);
|
||||||
|
|
||||||
|
std::cout << "Resolución nativa detectada: " << native_width << "x" << native_height << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Cargar PNG y escalar al tamaño especificado
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
unsigned char* LogoScaler::loadAndScale(const std::string& path,
|
||||||
|
int target_width, int target_height,
|
||||||
|
int& out_width, int& out_height) {
|
||||||
|
// 1. Intentar cargar imagen desde ResourceManager (pack o disco)
|
||||||
|
int orig_width, orig_height, orig_channels;
|
||||||
|
unsigned char* orig_data = nullptr;
|
||||||
|
|
||||||
|
// 1a. Cargar desde ResourceManager
|
||||||
|
unsigned char* resourceData = nullptr;
|
||||||
|
size_t resourceSize = 0;
|
||||||
|
|
||||||
|
if (ResourceManager::loadResource(path, resourceData, resourceSize)) {
|
||||||
|
// Descodificar imagen desde memoria usando stb_image
|
||||||
|
orig_data = stbi_load_from_memory(resourceData, static_cast<int>(resourceSize),
|
||||||
|
&orig_width, &orig_height, &orig_channels, STBI_rgb_alpha);
|
||||||
|
delete[] resourceData; // Liberar buffer temporal
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1b. Si falla todo, error
|
||||||
|
if (orig_data == nullptr) {
|
||||||
|
SDL_Log("Error al cargar imagen %s: %s", path.c_str(), stbi_failure_reason());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Imagen cargada: " << path << " (" << orig_width << "x" << orig_height << ")" << std::endl;
|
||||||
|
|
||||||
|
// 2. Calcular tamaño final manteniendo aspect ratio
|
||||||
|
// El alto está fijado por target_height (APPLOGO_HEIGHT_PERCENT)
|
||||||
|
// Calcular ancho proporcional al aspect ratio original
|
||||||
|
float aspect_ratio = static_cast<float>(orig_width) / static_cast<float>(orig_height);
|
||||||
|
out_width = static_cast<int>(target_height * aspect_ratio);
|
||||||
|
out_height = target_height;
|
||||||
|
|
||||||
|
std::cout << " Escalando a: " << out_width << "x" << out_height << std::endl;
|
||||||
|
|
||||||
|
// 3. Alocar buffer para imagen escalada (RGBA = 4 bytes por píxel)
|
||||||
|
unsigned char* scaled_data = static_cast<unsigned char*>(malloc(out_width * out_height * 4));
|
||||||
|
if (scaled_data == nullptr) {
|
||||||
|
SDL_Log("Error al alocar memoria para imagen escalada");
|
||||||
|
stbi_image_free(orig_data);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Escalar con stb_image_resize2 (algoritmo Mitchell, espacio sRGB)
|
||||||
|
// La función devuelve el puntero de salida, o nullptr si falla
|
||||||
|
unsigned char* result = stbir_resize_uint8_srgb(
|
||||||
|
orig_data, orig_width, orig_height, 0, // Input
|
||||||
|
scaled_data, out_width, out_height, 0, // Output
|
||||||
|
STBIR_RGBA // Formato píxel
|
||||||
|
);
|
||||||
|
|
||||||
|
// Liberar imagen original (ya no la necesitamos)
|
||||||
|
stbi_image_free(orig_data);
|
||||||
|
|
||||||
|
if (result == nullptr) {
|
||||||
|
SDL_Log("Error al escalar imagen");
|
||||||
|
free(scaled_data);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << " Escalado completado correctamente" << std::endl;
|
||||||
|
return scaled_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Crear textura SDL desde buffer RGBA
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
SDL_Texture* LogoScaler::createTextureFromBuffer(SDL_Renderer* renderer,
|
||||||
|
unsigned char* data,
|
||||||
|
int width, int height) {
|
||||||
|
if (renderer == nullptr || data == nullptr || width <= 0 || height <= 0) {
|
||||||
|
SDL_Log("Parámetros inválidos para createTextureFromBuffer");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Crear surface SDL desde buffer RGBA
|
||||||
|
int pitch = width * 4; // 4 bytes por píxel (RGBA)
|
||||||
|
SDL_PixelFormat pixel_format = SDL_PIXELFORMAT_RGBA32;
|
||||||
|
|
||||||
|
SDL_Surface* surface = SDL_CreateSurfaceFrom(
|
||||||
|
width, height,
|
||||||
|
pixel_format,
|
||||||
|
data,
|
||||||
|
pitch
|
||||||
|
);
|
||||||
|
|
||||||
|
if (surface == nullptr) {
|
||||||
|
SDL_Log("Error al crear surface: %s", SDL_GetError());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Crear textura desde surface
|
||||||
|
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
|
||||||
|
if (texture == nullptr) {
|
||||||
|
SDL_Log("Error al crear textura: %s", SDL_GetError());
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Liberar surface (la textura ya tiene los datos)
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
61
source/logo_scaler.hpp
Normal file
61
source/logo_scaler.hpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL_render.h> // Para SDL_Renderer, SDL_Texture
|
||||||
|
#include <SDL3/SDL_video.h> // Para SDL_DisplayID, SDL_GetDisplays
|
||||||
|
|
||||||
|
#include <string> // Para std::string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper class para pre-escalar logos usando stb_image_resize2
|
||||||
|
*
|
||||||
|
* Proporciona funciones para:
|
||||||
|
* - Detectar resolución nativa del monitor
|
||||||
|
* - Cargar PNG y escalar a tamaño específico con algoritmos de alta calidad
|
||||||
|
* - Crear texturas SDL desde buffers escalados
|
||||||
|
*
|
||||||
|
* Usado por AppLogo para pre-generar versiones de logos al tamaño exacto
|
||||||
|
* de pantalla, eliminando el escalado dinámico de SDL y mejorando calidad visual.
|
||||||
|
*/
|
||||||
|
class LogoScaler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Detecta la resolución nativa del monitor principal
|
||||||
|
*
|
||||||
|
* @param native_width [out] Ancho nativo del display en píxeles
|
||||||
|
* @param native_height [out] Alto nativo del display en píxeles
|
||||||
|
* @return true si se pudo detectar, false si hubo error
|
||||||
|
*/
|
||||||
|
static bool detectNativeResolution(int& native_width, int& native_height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Carga un PNG y lo escala al tamaño especificado
|
||||||
|
*
|
||||||
|
* Usa stb_image para cargar y stb_image_resize2 para escalar con
|
||||||
|
* algoritmo Mitchell (balance calidad/velocidad) en espacio sRGB.
|
||||||
|
*
|
||||||
|
* @param path Ruta al archivo PNG (ej: "data/logo/logo.png")
|
||||||
|
* @param target_width Ancho destino en píxeles
|
||||||
|
* @param target_height Alto destino en píxeles
|
||||||
|
* @param out_width [out] Ancho real de la imagen escalada
|
||||||
|
* @param out_height [out] Alto real de la imagen escalada
|
||||||
|
* @return Buffer RGBA (4 bytes por píxel) o nullptr si falla
|
||||||
|
* IMPORTANTE: El caller debe liberar con free() cuando termine
|
||||||
|
*/
|
||||||
|
static unsigned char* loadAndScale(const std::string& path,
|
||||||
|
int target_width, int target_height,
|
||||||
|
int& out_width, int& out_height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crea una textura SDL desde un buffer RGBA
|
||||||
|
*
|
||||||
|
* @param renderer Renderizador SDL activo
|
||||||
|
* @param data Buffer RGBA (4 bytes por píxel)
|
||||||
|
* @param width Ancho del buffer en píxeles
|
||||||
|
* @param height Alto del buffer en píxeles
|
||||||
|
* @return Textura SDL creada o nullptr si falla
|
||||||
|
* IMPORTANTE: El caller debe destruir con SDL_DestroyTexture()
|
||||||
|
*/
|
||||||
|
static SDL_Texture* createTextureFromBuffer(SDL_Renderer* renderer,
|
||||||
|
unsigned char* data,
|
||||||
|
int width, int height);
|
||||||
|
};
|
||||||
103
source/main.cpp
103
source/main.cpp
@@ -1,6 +1,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "engine.h"
|
#include <string>
|
||||||
|
#include "engine.hpp"
|
||||||
|
#include "defines.hpp"
|
||||||
|
#include "resource_manager.hpp"
|
||||||
|
|
||||||
// getExecutableDirectory() ya está definido en defines.h como inline
|
// getExecutableDirectory() ya está definido en defines.h como inline
|
||||||
|
|
||||||
@@ -11,13 +14,24 @@ void printHelp() {
|
|||||||
std::cout << " -w, --width <px> Ancho de resolución (default: 320)\n";
|
std::cout << " -w, --width <px> Ancho de resolución (default: 320)\n";
|
||||||
std::cout << " -h, --height <px> Alto de resolución (default: 240)\n";
|
std::cout << " -h, --height <px> Alto de resolución (default: 240)\n";
|
||||||
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\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 << " --help Mostrar esta ayuda\n\n";
|
std::cout << " --help Mostrar esta ayuda\n\n";
|
||||||
std::cout << "Ejemplos:\n";
|
std::cout << "Ejemplos:\n";
|
||||||
std::cout << " vibe3_physics # 320x240 zoom 3 (ventana 960x720)\n";
|
std::cout << " vibe3_physics # 320x240 zoom 3 (ventana 960x720)\n";
|
||||||
std::cout << " vibe3_physics -w 1920 -h 1080 # 1920x1080 zoom 1 (auto)\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 -w 640 -h 480 -z 2 # 640x480 zoom 2 (ventana 1280x960)\n";
|
||||||
std::cout << " vibe3_physics -w 1920 -h 1080 -f # 1920x1080 fullscreen\n\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";
|
std::cout << "Nota: Si resolución > pantalla, se usa default. Zoom se ajusta automáticamente.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +39,13 @@ int main(int argc, char* argv[]) {
|
|||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
int zoom = 0;
|
int zoom = 0;
|
||||||
|
int custom_balls = 0;
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
|
bool real_fullscreen = false;
|
||||||
|
bool kiosk_mode = false;
|
||||||
|
bool skip_benchmark = false;
|
||||||
|
int max_balls_override = 0;
|
||||||
|
AppMode initial_mode = AppMode::SANDBOX; // Modo inicial (default: SANDBOX)
|
||||||
|
|
||||||
// Parsear argumentos
|
// Parsear argumentos
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
@@ -35,8 +55,8 @@ int main(int argc, char* argv[]) {
|
|||||||
} else if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--width") == 0) {
|
} else if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--width") == 0) {
|
||||||
if (i + 1 < argc) {
|
if (i + 1 < argc) {
|
||||||
width = atoi(argv[++i]);
|
width = atoi(argv[++i]);
|
||||||
if (width < 640) {
|
if (width < 320) {
|
||||||
std::cerr << "Error: Ancho mínimo es 640px\n";
|
std::cerr << "Error: Ancho mínimo es 320\n";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -46,8 +66,8 @@ int main(int argc, char* argv[]) {
|
|||||||
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--height") == 0) {
|
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--height") == 0) {
|
||||||
if (i + 1 < argc) {
|
if (i + 1 < argc) {
|
||||||
height = atoi(argv[++i]);
|
height = atoi(argv[++i]);
|
||||||
if (height < 480) {
|
if (height < 240) {
|
||||||
std::cerr << "Error: Alto mínimo es 480px\n";
|
std::cerr << "Error: Alto mínimo es 240\n";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -67,6 +87,55 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
} else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--fullscreen") == 0) {
|
} else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--fullscreen") == 0) {
|
||||||
fullscreen = true;
|
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], "--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 {
|
} else {
|
||||||
std::cerr << "Error: Opción desconocida '" << argv[i] << "'\n";
|
std::cerr << "Error: Opción desconocida '" << argv[i] << "'\n";
|
||||||
printHelp();
|
printHelp();
|
||||||
@@ -77,15 +146,31 @@ int main(int argc, char* argv[]) {
|
|||||||
// Inicializar sistema de recursos empaquetados (intentar cargar resources.pack)
|
// Inicializar sistema de recursos empaquetados (intentar cargar resources.pack)
|
||||||
std::string resources_dir = getResourcesDirectory();
|
std::string resources_dir = getResourcesDirectory();
|
||||||
std::string pack_path = resources_dir + "/resources.pack";
|
std::string pack_path = resources_dir + "/resources.pack";
|
||||||
Texture::initResourceSystem(pack_path);
|
ResourceManager::init(pack_path);
|
||||||
|
|
||||||
Engine engine;
|
Engine engine;
|
||||||
|
|
||||||
if (!engine.initialize(width, height, zoom, fullscreen)) {
|
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 (!engine.initialize(width, height, zoom, fullscreen, initial_mode)) {
|
||||||
std::cout << "¡Error al inicializar el engine!" << std::endl;
|
std::cout << "¡Error al inicializar el engine!" << std::endl;
|
||||||
return -1;
|
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.run();
|
||||||
engine.shutdown();
|
engine.shutdown();
|
||||||
|
|
||||||
|
|||||||
99
source/resource_manager.cpp
Normal file
99
source/resource_manager.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "resource_manager.hpp"
|
||||||
|
#include "resource_pack.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
// Inicializar estáticos
|
||||||
|
ResourcePack* ResourceManager::resourcePack_ = nullptr;
|
||||||
|
std::map<std::string, std::vector<unsigned char>> ResourceManager::cache_;
|
||||||
|
|
||||||
|
bool ResourceManager::init(const std::string& packFilePath) {
|
||||||
|
// Si ya estaba inicializado, liberar primero
|
||||||
|
if (resourcePack_ != nullptr) {
|
||||||
|
delete resourcePack_;
|
||||||
|
resourcePack_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentar cargar el pack
|
||||||
|
resourcePack_ = new ResourcePack();
|
||||||
|
if (!resourcePack_->loadPack(packFilePath)) {
|
||||||
|
// Si falla, borrar instancia (usará fallback a disco)
|
||||||
|
delete resourcePack_;
|
||||||
|
resourcePack_ = nullptr;
|
||||||
|
std::cout << "resources.pack no encontrado - usando carpeta data/" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "resources.pack cargado (" << resourcePack_->getResourceCount() << " recursos)" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::shutdown() {
|
||||||
|
cache_.clear();
|
||||||
|
if (resourcePack_ != nullptr) {
|
||||||
|
delete resourcePack_;
|
||||||
|
resourcePack_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceManager::loadResource(const std::string& resourcePath, unsigned char*& data, size_t& size) {
|
||||||
|
data = nullptr;
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
ResourcePack::ResourceData packData = resourcePack_->loadResource(resourcePath);
|
||||||
|
if (packData.data != nullptr) {
|
||||||
|
cache_[resourcePath] = std::vector<unsigned char>(packData.data, packData.data + packData.size);
|
||||||
|
data = packData.data;
|
||||||
|
size = packData.size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Fallback: cargar desde disco
|
||||||
|
std::ifstream file(resourcePath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) {
|
||||||
|
std::string dataPath = "data/" + resourcePath;
|
||||||
|
file.open(dataPath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) { return false; }
|
||||||
|
}
|
||||||
|
size = static_cast<size_t>(file.tellg());
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
data = new unsigned char[size];
|
||||||
|
file.read(reinterpret_cast<char*>(data), size);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
// Guardar en caché
|
||||||
|
cache_[resourcePath] = std::vector<unsigned char>(data, data + size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceManager::isPackLoaded() {
|
||||||
|
return resourcePack_ != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ResourceManager::getResourceList() {
|
||||||
|
if (resourcePack_ != nullptr) {
|
||||||
|
return resourcePack_->getResourceList();
|
||||||
|
}
|
||||||
|
return std::vector<std::string>(); // Vacío si no hay pack
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ResourceManager::getResourceCount() {
|
||||||
|
if (resourcePack_ != nullptr) {
|
||||||
|
return resourcePack_->getResourceCount();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
86
source/resource_manager.hpp
Normal file
86
source/resource_manager.hpp
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ResourcePack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResourceManager - Gestor centralizado de recursos empaquetados
|
||||||
|
*
|
||||||
|
* Singleton que administra el sistema de recursos empaquetados (resources.pack)
|
||||||
|
* y proporciona fallback automático a disco cuando el pack no está disponible.
|
||||||
|
*
|
||||||
|
* Uso:
|
||||||
|
* // En main.cpp, antes de inicializar cualquier sistema:
|
||||||
|
* ResourceManager::init("resources.pack");
|
||||||
|
*
|
||||||
|
* // Desde cualquier clase que necesite recursos:
|
||||||
|
* unsigned char* data = nullptr;
|
||||||
|
* size_t size = 0;
|
||||||
|
* if (ResourceManager::loadResource("textures/ball.png", data, size)) {
|
||||||
|
* // Usar datos...
|
||||||
|
* delete[] data; // Liberar cuando termine
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
class ResourceManager {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Inicializa el sistema de recursos empaquetados
|
||||||
|
* Debe llamarse una única vez al inicio del programa
|
||||||
|
*
|
||||||
|
* @param packFilePath Ruta al archivo .pack (ej: "resources.pack")
|
||||||
|
* @return true si el pack se cargó correctamente, false si no existe (fallback a disco)
|
||||||
|
*/
|
||||||
|
static bool init(const std::string& packFilePath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Libera el sistema de recursos
|
||||||
|
* Opcional - se llama automáticamente al cerrar el programa
|
||||||
|
*/
|
||||||
|
static void shutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Carga un recurso desde el pack (o disco si no existe pack)
|
||||||
|
*
|
||||||
|
* @param resourcePath Ruta relativa del recurso (ej: "textures/ball.png")
|
||||||
|
* @param data [out] Puntero donde se almacenará el buffer (debe liberar con delete[])
|
||||||
|
* @param size [out] Tamaño del buffer en bytes
|
||||||
|
* @return true si se cargó correctamente, false si falla
|
||||||
|
*/
|
||||||
|
static bool loadResource(const std::string& resourcePath, unsigned char*& data, size_t& size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifica si el pack está cargado
|
||||||
|
* @return true si hay un pack cargado, false si se usa disco
|
||||||
|
*/
|
||||||
|
static bool isPackLoaded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene la lista de recursos disponibles en el pack
|
||||||
|
* @return Vector con las rutas de todos los recursos, vacío si no hay pack
|
||||||
|
*/
|
||||||
|
static std::vector<std::string> getResourceList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene el número de recursos en el pack
|
||||||
|
* @return Número de recursos, 0 si no hay pack
|
||||||
|
*/
|
||||||
|
static size_t getResourceCount();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Constructor privado (singleton)
|
||||||
|
ResourceManager() = default;
|
||||||
|
~ResourceManager() = default;
|
||||||
|
|
||||||
|
// Deshabilitar copia y asignación
|
||||||
|
ResourceManager(const ResourceManager&) = delete;
|
||||||
|
ResourceManager& operator=(const ResourceManager&) = delete;
|
||||||
|
|
||||||
|
// Instancia del pack (nullptr si no está cargado)
|
||||||
|
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_;
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "resource_pack.h"
|
#include "resource_pack.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef RESOURCE_PACK_H
|
#pragma once
|
||||||
#define RESOURCE_PACK_H
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -64,5 +63,3 @@ private:
|
|||||||
uint32_t calculateChecksum(const unsigned char* data, size_t size);
|
uint32_t calculateChecksum(const unsigned char* data, size_t size);
|
||||||
std::string normalizePath(const std::string& path);
|
std::string normalizePath(const std::string& path);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RESOURCE_PACK_H
|
|
||||||
241
source/scene/scene_manager.cpp
Normal file
241
source/scene/scene_manager.cpp
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
#include "scene_manager.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib> // for rand
|
||||||
|
|
||||||
|
#include "defines.hpp" // for BALL_COUNT_SCENARIOS, GRAVITY_MASS_MIN, etc
|
||||||
|
#include "external/texture.hpp" // for Texture
|
||||||
|
#include "theme_manager.hpp" // for ThemeManager
|
||||||
|
|
||||||
|
SceneManager::SceneManager(int screen_width, int screen_height)
|
||||||
|
: current_gravity_(GravityDirection::DOWN)
|
||||||
|
, scenario_(0)
|
||||||
|
, screen_width_(screen_width)
|
||||||
|
, screen_height_(screen_height)
|
||||||
|
, current_ball_size_(10)
|
||||||
|
, texture_(nullptr)
|
||||||
|
, theme_manager_(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::initialize(int scenario, std::shared_ptr<Texture> texture, ThemeManager* theme_manager) {
|
||||||
|
scenario_ = scenario;
|
||||||
|
texture_ = texture;
|
||||||
|
theme_manager_ = theme_manager;
|
||||||
|
current_ball_size_ = texture_->getWidth();
|
||||||
|
|
||||||
|
// Crear bolas iniciales (siempre en modo PHYSICS al inicio)
|
||||||
|
changeScenario(scenario_, SimulationMode::PHYSICS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::update(float delta_time) {
|
||||||
|
// Actualizar física de todas las bolas
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->update(delta_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::changeScenario(int scenario_id, SimulationMode mode) {
|
||||||
|
// Guardar escenario
|
||||||
|
scenario_ = scenario_id;
|
||||||
|
|
||||||
|
// Limpiar las bolas actuales
|
||||||
|
balls_.clear();
|
||||||
|
|
||||||
|
// Resetear gravedad al estado por defecto (DOWN) al cambiar escenario
|
||||||
|
changeGravityDirection(GravityDirection::DOWN);
|
||||||
|
|
||||||
|
// Crear las bolas según el escenario
|
||||||
|
int ball_count = (scenario_id == CUSTOM_SCENARIO_IDX)
|
||||||
|
? custom_ball_count_
|
||||||
|
: BALL_COUNT_SCENARIOS[scenario_id];
|
||||||
|
for (int i = 0; i < ball_count; ++i) {
|
||||||
|
float X, Y, VX, VY;
|
||||||
|
|
||||||
|
// Inicialización según SimulationMode (RULES.md líneas 23-26)
|
||||||
|
switch (mode) {
|
||||||
|
case SimulationMode::PHYSICS: {
|
||||||
|
// PHYSICS: Parte superior, 75% distribución central en X
|
||||||
|
const int SIGN = ((rand() % 2) * 2) - 1;
|
||||||
|
const int margin = static_cast<int>(screen_width_ * BALL_SPAWN_MARGIN);
|
||||||
|
const int spawn_zone_width = screen_width_ - (2 * margin);
|
||||||
|
X = (rand() % spawn_zone_width) + margin;
|
||||||
|
Y = 0.0f; // Parte superior
|
||||||
|
VX = (((rand() % 20) + 10) * 0.1f) * SIGN;
|
||||||
|
VY = ((rand() % 60) - 30) * 0.1f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SimulationMode::SHAPE: {
|
||||||
|
// SHAPE: Centro de pantalla, sin velocidad inicial
|
||||||
|
X = screen_width_ / 2.0f;
|
||||||
|
Y = screen_height_ / 2.0f; // Centro vertical
|
||||||
|
VX = 0.0f;
|
||||||
|
VY = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SimulationMode::BOIDS: {
|
||||||
|
// BOIDS: Posiciones aleatorias, velocidades aleatorias
|
||||||
|
const int SIGN_X = ((rand() % 2) * 2) - 1;
|
||||||
|
const int SIGN_Y = ((rand() % 2) * 2) - 1;
|
||||||
|
X = static_cast<float>(rand() % screen_width_);
|
||||||
|
Y = static_cast<float>(rand() % screen_height_); // Posición Y aleatoria
|
||||||
|
VX = (((rand() % 40) + 10) * 0.1f) * SIGN_X; // 1.0 - 5.0 px/frame
|
||||||
|
VY = (((rand() % 40) + 10) * 0.1f) * SIGN_Y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Fallback a PHYSICS por seguridad
|
||||||
|
const int SIGN = ((rand() % 2) * 2) - 1;
|
||||||
|
const int margin = static_cast<int>(screen_width_ * BALL_SPAWN_MARGIN);
|
||||||
|
const int spawn_zone_width = screen_width_ - (2 * margin);
|
||||||
|
X = (rand() % spawn_zone_width) + margin;
|
||||||
|
Y = 0.0f; // Parte superior
|
||||||
|
VX = (((rand() % 20) + 10) * 0.1f) * SIGN;
|
||||||
|
VY = ((rand() % 60) - 30) * 0.1f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seleccionar color de la paleta del tema actual (delegado a ThemeManager)
|
||||||
|
int random_index = rand();
|
||||||
|
Color COLOR = theme_manager_->getInitialBallColor(random_index);
|
||||||
|
|
||||||
|
// Generar factor de masa aleatorio (0.7 = ligera, 1.3 = pesada)
|
||||||
|
float mass_factor = GRAVITY_MASS_MIN + (rand() % 1000) / 1000.0f * (GRAVITY_MASS_MAX - GRAVITY_MASS_MIN);
|
||||||
|
|
||||||
|
balls_.emplace_back(std::make_unique<Ball>(
|
||||||
|
X, Y, VX, VY, COLOR, texture_,
|
||||||
|
screen_width_, screen_height_, current_ball_size_,
|
||||||
|
current_gravity_, mass_factor
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::updateBallTexture(std::shared_ptr<Texture> new_texture, int new_ball_size) {
|
||||||
|
if (balls_.empty()) return;
|
||||||
|
|
||||||
|
// Guardar tamaño antiguo
|
||||||
|
int old_size = current_ball_size_;
|
||||||
|
|
||||||
|
// Actualizar textura y tamaño
|
||||||
|
texture_ = new_texture;
|
||||||
|
current_ball_size_ = new_ball_size;
|
||||||
|
|
||||||
|
// Actualizar texturas de todas las pelotas
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->setTexture(texture_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajustar posiciones según el cambio de tamaño
|
||||||
|
updateBallSizes(old_size, new_ball_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::pushBallsAwayFromGravity() {
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
const int SIGNO = ((rand() % 2) * 2) - 1;
|
||||||
|
const float LATERAL = (((rand() % 20) + 10) * 0.1f) * SIGNO;
|
||||||
|
const float MAIN = ((rand() % 40) * 0.1f) + 5;
|
||||||
|
|
||||||
|
float vx = 0, vy = 0;
|
||||||
|
switch (current_gravity_) {
|
||||||
|
case GravityDirection::DOWN: // Impulsar ARRIBA
|
||||||
|
vx = LATERAL;
|
||||||
|
vy = -MAIN;
|
||||||
|
break;
|
||||||
|
case GravityDirection::UP: // Impulsar ABAJO
|
||||||
|
vx = LATERAL;
|
||||||
|
vy = MAIN;
|
||||||
|
break;
|
||||||
|
case GravityDirection::LEFT: // Impulsar DERECHA
|
||||||
|
vx = MAIN;
|
||||||
|
vy = LATERAL;
|
||||||
|
break;
|
||||||
|
case GravityDirection::RIGHT: // Impulsar IZQUIERDA
|
||||||
|
vx = -MAIN;
|
||||||
|
vy = LATERAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ball->modVel(vx, vy); // Modifica la velocidad según dirección de gravedad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::switchBallsGravity() {
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->switchGravity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::enableBallsGravityIfDisabled() {
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->enableGravityIfDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::forceBallsGravityOn() {
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->forceGravityOn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::forceBallsGravityOff() {
|
||||||
|
// Contar cuántas pelotas están en superficie (suelo/techo/pared)
|
||||||
|
int balls_on_surface = 0;
|
||||||
|
for (const auto& ball : balls_) {
|
||||||
|
if (ball->isOnSurface()) {
|
||||||
|
balls_on_surface++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si la mayoría (>50%) están en superficie, aplicar impulso para que se vea el efecto
|
||||||
|
float surface_ratio = static_cast<float>(balls_on_surface) / static_cast<float>(balls_.size());
|
||||||
|
if (surface_ratio > 0.5f) {
|
||||||
|
pushBallsAwayFromGravity(); // Dar impulso contrario a gravedad
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desactivar gravedad
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->forceGravityOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::changeGravityDirection(GravityDirection direction) {
|
||||||
|
current_gravity_ = direction;
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
ball->setGravityDirection(direction);
|
||||||
|
ball->applyRandomLateralPush(); // Aplicar empuje lateral aleatorio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SceneManager::updateScreenSize(int width, int height) {
|
||||||
|
screen_width_ = width;
|
||||||
|
screen_height_ = height;
|
||||||
|
|
||||||
|
// NOTA: No actualizamos las bolas existentes, solo afecta a futuras creaciones
|
||||||
|
// Si se requiere reposicionar bolas existentes, implementar aquí
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Métodos privados ===
|
||||||
|
|
||||||
|
void SceneManager::updateBallSizes(int old_size, int new_size) {
|
||||||
|
for (auto& ball : balls_) {
|
||||||
|
SDL_FRect pos = ball->getPosition();
|
||||||
|
|
||||||
|
// Ajustar posición para compensar cambio de tamaño
|
||||||
|
// Si aumenta tamaño, mover hacia centro; si disminuye, alejar del centro
|
||||||
|
float center_x = screen_width_ / 2.0f;
|
||||||
|
float center_y = screen_height_ / 2.0f;
|
||||||
|
|
||||||
|
float dx = pos.x - center_x;
|
||||||
|
float dy = pos.y - center_y;
|
||||||
|
|
||||||
|
// Ajustar proporcionalmente (evitar divisiones por cero)
|
||||||
|
if (old_size > 0) {
|
||||||
|
float scale_factor = static_cast<float>(new_size) / static_cast<float>(old_size);
|
||||||
|
pos.x = center_x + dx * scale_factor;
|
||||||
|
pos.y = center_y + dy * scale_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actualizar tamaño del hitbox
|
||||||
|
ball->updateSize(new_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
174
source/scene/scene_manager.hpp
Normal file
174
source/scene/scene_manager.hpp
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory> // for unique_ptr, shared_ptr
|
||||||
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ball.hpp" // for Ball
|
||||||
|
#include "defines.hpp" // for GravityDirection
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Texture;
|
||||||
|
class ThemeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class SceneManager
|
||||||
|
* @brief Gestiona toda la lógica de creación, física y actualización de bolas
|
||||||
|
*
|
||||||
|
* Responsabilidad única: Manejo de la escena (bolas, gravedad, física)
|
||||||
|
*
|
||||||
|
* Características:
|
||||||
|
* - Crea y destruye bolas según escenario seleccionado
|
||||||
|
* - Controla la dirección y estado de la gravedad
|
||||||
|
* - Actualiza física de todas las bolas cada frame
|
||||||
|
* - Proporciona acceso controlado a las bolas para rendering
|
||||||
|
* - Mantiene el Engine desacoplado de la lógica de física
|
||||||
|
*/
|
||||||
|
class SceneManager {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
* @param screen_width Ancho lógico de la pantalla
|
||||||
|
* @param screen_height Alto lógico de la pantalla
|
||||||
|
*/
|
||||||
|
SceneManager(int screen_width, int screen_height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inicializa el manager con configuración inicial
|
||||||
|
* @param scenario Escenario inicial (índice de BALL_COUNT_SCENARIOS)
|
||||||
|
* @param texture Textura compartida para sprites de bolas
|
||||||
|
* @param theme_manager Puntero al gestor de temas (para colores)
|
||||||
|
*/
|
||||||
|
void initialize(int scenario, std::shared_ptr<Texture> texture, ThemeManager* theme_manager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actualiza física de todas las bolas
|
||||||
|
* @param delta_time Tiempo transcurrido desde último frame (segundos)
|
||||||
|
*/
|
||||||
|
void update(float delta_time);
|
||||||
|
|
||||||
|
// === Gestión de bolas ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cambia el número de bolas según escenario
|
||||||
|
* @param scenario_id Índice del escenario (0-7 para 10 a 50,000 bolas; 8 = custom)
|
||||||
|
* @param mode Modo de simulación actual (afecta inicialización)
|
||||||
|
*/
|
||||||
|
void changeScenario(int scenario_id, SimulationMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configura el número de bolas para el escenario custom (índice 8)
|
||||||
|
* @param n Número de bolas del escenario custom
|
||||||
|
*/
|
||||||
|
void setCustomBallCount(int n) { custom_ball_count_ = n; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actualiza textura y tamaño de todas las bolas
|
||||||
|
* @param new_texture Nueva textura compartida
|
||||||
|
* @param new_ball_size Nuevo tamaño de bolas (píxeles)
|
||||||
|
*/
|
||||||
|
void updateBallTexture(std::shared_ptr<Texture> new_texture, int new_ball_size);
|
||||||
|
|
||||||
|
// === Control de gravedad ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Aplica impulso a todas las bolas alejándolas de la superficie de gravedad
|
||||||
|
*/
|
||||||
|
void pushBallsAwayFromGravity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Alterna el estado de gravedad (ON/OFF) en todas las bolas
|
||||||
|
*/
|
||||||
|
void switchBallsGravity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reactiva gravedad solo si estaba desactivada
|
||||||
|
*/
|
||||||
|
void enableBallsGravityIfDisabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fuerza gravedad ON en todas las bolas
|
||||||
|
*/
|
||||||
|
void forceBallsGravityOn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fuerza gravedad OFF en todas las bolas (con impulso si >50% en superficie)
|
||||||
|
*/
|
||||||
|
void forceBallsGravityOff();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cambia la dirección de la gravedad
|
||||||
|
* @param direction Nueva dirección (UP/DOWN/LEFT/RIGHT)
|
||||||
|
*/
|
||||||
|
void changeGravityDirection(GravityDirection direction);
|
||||||
|
|
||||||
|
// === Acceso a datos (read-only) ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtiene referencia constante al vector de bolas (para rendering)
|
||||||
|
*/
|
||||||
|
const std::vector<std::unique_ptr<Ball>>& getBalls() const { return balls_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtiene referencia mutable al vector de bolas (para ShapeManager)
|
||||||
|
* NOTA: Usar con cuidado, solo para sistemas que necesitan modificar estado de bolas
|
||||||
|
*/
|
||||||
|
std::vector<std::unique_ptr<Ball>>& getBallsMutable() { return balls_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtiene número total de bolas
|
||||||
|
*/
|
||||||
|
size_t getBallCount() const { return balls_.size(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verifica si hay al menos una bola
|
||||||
|
*/
|
||||||
|
bool hasBalls() const { return !balls_.empty(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtiene puntero a la primera bola (para debug info)
|
||||||
|
* @return Puntero constante o nullptr si no hay bolas
|
||||||
|
*/
|
||||||
|
const Ball* getFirstBall() const { return balls_.empty() ? nullptr : balls_[0].get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtiene dirección actual de gravedad
|
||||||
|
*/
|
||||||
|
GravityDirection getCurrentGravity() const { return current_gravity_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtiene escenario actual
|
||||||
|
*/
|
||||||
|
int getCurrentScenario() const { return scenario_; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actualiza resolución de pantalla (para resize/fullscreen)
|
||||||
|
* @param width Nuevo ancho lógico
|
||||||
|
* @param height Nuevo alto lógico
|
||||||
|
*/
|
||||||
|
void updateScreenSize(int width, int height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// === Datos de escena ===
|
||||||
|
std::vector<std::unique_ptr<Ball>> balls_;
|
||||||
|
GravityDirection current_gravity_;
|
||||||
|
int scenario_;
|
||||||
|
int custom_ball_count_ = 0; // Número de bolas para escenario custom (índice 8)
|
||||||
|
|
||||||
|
// === Configuración de pantalla ===
|
||||||
|
int screen_width_;
|
||||||
|
int screen_height_;
|
||||||
|
int current_ball_size_;
|
||||||
|
|
||||||
|
// === Referencias a otros sistemas (no owned) ===
|
||||||
|
std::shared_ptr<Texture> texture_;
|
||||||
|
ThemeManager* theme_manager_;
|
||||||
|
|
||||||
|
// === Métodos privados auxiliares ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ajusta posiciones de bolas al cambiar tamaño de sprite
|
||||||
|
* @param old_size Tamaño anterior
|
||||||
|
* @param new_size Tamaño nuevo
|
||||||
|
*/
|
||||||
|
void updateBallSizes(int old_size, int new_size);
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "atom_shape.h"
|
#include "atom_shape.hpp"
|
||||||
#include "../defines.h"
|
#include "defines.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
void AtomShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
void AtomShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "shape.h"
|
#include "shape.hpp"
|
||||||
|
|
||||||
// Figura: Átomo con núcleo central y órbitas electrónicas
|
// Figura: Átomo con núcleo central y órbitas electrónicas
|
||||||
// Comportamiento: Núcleo estático + electrones orbitando en planos inclinados
|
// Comportamiento: Núcleo estático + electrones orbitando en planos inclinados
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "cube_shape.h"
|
#include "cube_shape.hpp"
|
||||||
#include "../defines.h"
|
#include "defines.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
void CubeShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
void CubeShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "shape.h"
|
#include "shape.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// Figura: Cubo 3D rotante
|
// Figura: Cubo 3D rotante
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "cylinder_shape.h"
|
#include "cylinder_shape.hpp"
|
||||||
#include "../defines.h"
|
#include "defines.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib> // Para rand()
|
#include <cstdlib> // Para rand()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "shape.h"
|
#include "shape.hpp"
|
||||||
|
|
||||||
// Figura: Cilindro 3D rotante
|
// Figura: Cilindro 3D rotante
|
||||||
// Comportamiento: Superficie cilíndrica con rotación en eje Y + tumbling ocasional en X/Z
|
// Comportamiento: Superficie cilíndrica con rotación en eje Y + tumbling ocasional en X/Z
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user