Compare commits
40 Commits
7fac103c51
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
17
.gitignore
vendored
17
.gitignore
vendored
@@ -94,3 +94,20 @@ Thumbs.db
|
||||
|
||||
# Claude Code
|
||||
.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
|
||||
709
BOIDS_ROADMAP.md
709
BOIDS_ROADMAP.md
@@ -1,709 +0,0 @@
|
||||
# BOIDS ROADMAP - Plan de Mejora Completo
|
||||
|
||||
**Proyecto:** ViBe3 Physics - Sistema de Boids (Flocking Behavior)
|
||||
**Fecha de creación:** 2025-01-XX
|
||||
**Estado actual:** Implementación básica funcional pero con problemas críticos
|
||||
|
||||
---
|
||||
|
||||
## 📊 Diagnóstico de Problemas Actuales
|
||||
|
||||
### 🔴 CRÍTICO: Bug de Clustering (Colapso a Punto Único)
|
||||
|
||||
**Problema observado:**
|
||||
- Los boids se agrupan correctamente en grupos separados
|
||||
- **PERO** dentro de cada grupo, todos colapsan al mismo punto exacto
|
||||
- Las pelotas se superponen completamente, formando una "masa" sin espacio entre ellas
|
||||
|
||||
**Causa raíz identificada:**
|
||||
1. **Desbalance de fuerzas**: Cohesión (80px radio) domina sobre Separación (30px radio)
|
||||
2. **Aplicación de fuerzas**: Se aplican fuerzas cada frame sin velocidad mínima
|
||||
3. **Fuerza máxima muy baja**: `BOID_MAX_FORCE = 0.1` es insuficiente para separación efectiva
|
||||
4. **Sin velocidad mínima**: Los boids pueden quedarse completamente estáticos (vx=0, vy=0)
|
||||
|
||||
**Impacto:** Sistema de boids inutilizable visualmente
|
||||
|
||||
---
|
||||
|
||||
### 🔴 CRÍTICO: Rendimiento O(n²) Inaceptable
|
||||
|
||||
**Problema observado:**
|
||||
- 100 boids: ~60 FPS ✅
|
||||
- 1,000 boids: ~15-20 FPS ❌ (caída del 70%)
|
||||
- 5,000+ boids: < 5 FPS ❌ (completamente inutilizable)
|
||||
|
||||
**Causa raíz identificada:**
|
||||
```cpp
|
||||
// Cada boid revisa TODOS los demás boids (3 veces: separation, alignment, cohesion)
|
||||
for (auto& boid : balls) {
|
||||
applySeparation(boid); // O(n) - itera todos los balls
|
||||
applyAlignment(boid); // O(n) - itera todos los balls
|
||||
applyCohesion(boid); // O(n) - itera todos los balls
|
||||
}
|
||||
// Complejidad total: O(n²) × 3 = O(3n²)
|
||||
```
|
||||
|
||||
**Cálculos de complejidad:**
|
||||
- 100 boids: 100 × 100 × 3 = **30,000 checks/frame**
|
||||
- 1,000 boids: 1,000 × 1,000 × 3 = **3,000,000 checks/frame** (100x más lento)
|
||||
- 10,000 boids: 10,000 × 10,000 × 3 = **300,000,000 checks/frame** (imposible)
|
||||
|
||||
**Impacto:** No escalable más allá de ~500 boids
|
||||
|
||||
---
|
||||
|
||||
### 🟡 MEDIO: Comportamiento Visual Pobre
|
||||
|
||||
**Problemas identificados:**
|
||||
1. **Sin variedad visual**: Todos los boids idénticos (mismo tamaño, color)
|
||||
2. **Movimiento robótico**: Steering demasiado directo, sin suavizado
|
||||
3. **Wrapping abrupto**: Teletransporte visible rompe inmersión
|
||||
4. **Sin personalidad**: Todos los boids se comportan idénticamente
|
||||
|
||||
**Impacto:** Resultado visual poco interesante y repetitivo
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Plan de Fases de Mejora
|
||||
|
||||
---
|
||||
|
||||
## **FASE 1: Fix Clustering Bug (CRÍTICO)** ⚠️
|
||||
|
||||
**Objetivo:** Eliminar el colapso a punto único, mantener grupos dispersos
|
||||
|
||||
**Prioridad:** CRÍTICA
|
||||
**Tiempo estimado:** 2-3 horas
|
||||
**Complejidad:** Baja (ajustes de parámetros + lógica mínima)
|
||||
|
||||
### Cambios a Implementar
|
||||
|
||||
#### 1.1 Rebalanceo de Radios y Pesos
|
||||
|
||||
**Problema actual:**
|
||||
```cpp
|
||||
// defines.h - VALORES ACTUALES (INCORRECTOS)
|
||||
BOID_SEPARATION_RADIUS = 30.0f; // Radio muy pequeño
|
||||
BOID_ALIGNMENT_RADIUS = 50.0f;
|
||||
BOID_COHESION_RADIUS = 80.0f; // Radio muy grande (domina)
|
||||
BOID_SEPARATION_WEIGHT = 1.5f; // Peso insuficiente
|
||||
BOID_ALIGNMENT_WEIGHT = 1.0f;
|
||||
BOID_COHESION_WEIGHT = 0.8f;
|
||||
BOID_MAX_FORCE = 0.1f; // Fuerza máxima muy débil
|
||||
BOID_MAX_SPEED = 3.0f;
|
||||
```
|
||||
|
||||
**Solución propuesta:**
|
||||
```cpp
|
||||
// defines.h - VALORES CORREGIDOS
|
||||
BOID_SEPARATION_RADIUS = 25.0f; // Radio pequeño pero suficiente
|
||||
BOID_ALIGNMENT_RADIUS = 40.0f;
|
||||
BOID_COHESION_RADIUS = 60.0f; // Reducido (menos dominante)
|
||||
BOID_SEPARATION_WEIGHT = 3.0f; // TRIPLICADO (alta prioridad)
|
||||
BOID_ALIGNMENT_WEIGHT = 1.0f; // Sin cambios
|
||||
BOID_COHESION_WEIGHT = 0.5f; // REDUCIDO a la mitad
|
||||
BOID_MAX_FORCE = 0.5f; // QUINTUPLICADO (permite reacción rápida)
|
||||
BOID_MAX_SPEED = 3.0f; // Sin cambios
|
||||
BOID_MIN_SPEED = 0.5f; // NUEVO: velocidad mínima
|
||||
```
|
||||
|
||||
**Justificación:**
|
||||
- **Separation dominante**: Evita colapso con peso 3x mayor
|
||||
- **Cohesion reducida**: Radio 60px (antes 80px) + peso 0.5 (antes 0.8)
|
||||
- **Max force aumentada**: Permite correcciones rápidas
|
||||
- **Min speed añadida**: Evita boids estáticos
|
||||
|
||||
#### 1.2 Implementar Velocidad Mínima
|
||||
|
||||
**Archivo:** `source/boids_mgr/boid_manager.cpp`
|
||||
|
||||
**Añadir al final de `limitSpeed()`:**
|
||||
```cpp
|
||||
void BoidManager::limitSpeed(Ball* boid) {
|
||||
float vx, vy;
|
||||
boid->getVelocity(vx, vy);
|
||||
|
||||
float speed = std::sqrt(vx * vx + vy * vy);
|
||||
|
||||
// Limitar velocidad máxima
|
||||
if (speed > BOID_MAX_SPEED) {
|
||||
vx = (vx / speed) * BOID_MAX_SPEED;
|
||||
vy = (vy / speed) * BOID_MAX_SPEED;
|
||||
boid->setVelocity(vx, vy);
|
||||
}
|
||||
|
||||
// NUEVO: Aplicar velocidad mínima (evitar boids estáticos)
|
||||
if (speed > 0.0f && speed < BOID_MIN_SPEED) {
|
||||
vx = (vx / speed) * BOID_MIN_SPEED;
|
||||
vy = (vy / speed) * BOID_MIN_SPEED;
|
||||
boid->setVelocity(vx, vy);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 1.3 Mejorar Aplicación de Fuerza de Separación
|
||||
|
||||
**Problema actual:** Separación se divide por distancia² (muy débil cuando cerca)
|
||||
|
||||
**Archivo:** `source/boids_mgr/boid_manager.cpp::applySeparation()`
|
||||
|
||||
**Cambio:**
|
||||
```cpp
|
||||
// ANTES (línea 145):
|
||||
steer_x += (dx / distance) / distance; // Dividir por distance² hace fuerza muy débil
|
||||
steer_y += (dy / distance) / distance;
|
||||
|
||||
// DESPUÉS:
|
||||
// Separación más fuerte cuando más cerca (inversa de distancia, no cuadrado)
|
||||
float separation_strength = (BOID_SEPARATION_RADIUS - distance) / BOID_SEPARATION_RADIUS;
|
||||
steer_x += (dx / distance) * separation_strength;
|
||||
steer_y += (dy / distance) * separation_strength;
|
||||
```
|
||||
|
||||
**Justificación:** Fuerza de separación ahora es proporcional a cercanía (0% en radio máximo, 100% en colisión)
|
||||
|
||||
### Testing de Fase 1
|
||||
|
||||
**Checklist de validación:**
|
||||
- [ ] Con 100 boids: Grupos visibles con espacio entre boids individuales
|
||||
- [ ] Con 1000 boids: Sin colapso a puntos únicos
|
||||
- [ ] Ningún boid completamente estático (velocidad > 0.5)
|
||||
- [ ] Distancia mínima entre boids vecinos: ~10-15px
|
||||
- [ ] FPS con 1000 boids: ~15-20 FPS (sin mejorar, pero funcional)
|
||||
|
||||
**Criterio de éxito:**
|
||||
✅ Los boids mantienen distancia personal dentro de grupos sin colapsar
|
||||
|
||||
---
|
||||
|
||||
## **FASE 2: Spatial Hash Grid (ALTO IMPACTO)** 🚀 ✅ **COMPLETADA**
|
||||
|
||||
**Objetivo:** O(n²) → O(n) mediante optimización espacial
|
||||
|
||||
**Prioridad:** ALTA
|
||||
**Tiempo estimado:** 4-6 horas → **Real: 2 horas**
|
||||
**Complejidad:** Media (nueva estructura de datos)
|
||||
|
||||
### Concepto: Spatial Hash Grid
|
||||
|
||||
**Problema actual:**
|
||||
```
|
||||
Cada boid revisa TODOS los demás boids
|
||||
→ 1000 boids × 1000 checks = 1,000,000 comparaciones
|
||||
```
|
||||
|
||||
**Solución:**
|
||||
```
|
||||
Dividir espacio en grid de celdas
|
||||
Cada boid solo revisa boids en celdas vecinas (3×3 = 9 celdas)
|
||||
→ 1000 boids × ~10 vecinos = 10,000 comparaciones (100x más rápido)
|
||||
```
|
||||
|
||||
### Implementación
|
||||
|
||||
#### 2.1 Crear Estructura de Spatial Grid
|
||||
|
||||
**Nuevo archivo:** `source/boids_mgr/spatial_grid.h`
|
||||
```cpp
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class Ball;
|
||||
|
||||
// Clase para optimización espacial de búsqueda de vecinos
|
||||
class SpatialGrid {
|
||||
public:
|
||||
SpatialGrid(int screen_width, int screen_height, float cell_size);
|
||||
|
||||
void clear();
|
||||
void insert(Ball* boid);
|
||||
std::vector<Ball*> getNearby(Ball* boid, float radius);
|
||||
|
||||
private:
|
||||
int screen_width_;
|
||||
int screen_height_;
|
||||
float cell_size_;
|
||||
int grid_width_;
|
||||
int grid_height_;
|
||||
|
||||
// Hash map: cell_id → vector de boids en esa celda
|
||||
std::unordered_map<int, std::vector<Ball*>> grid_;
|
||||
|
||||
int getCellId(float x, float y) const;
|
||||
void getCellCoords(int cell_id, int& cx, int& cy) const;
|
||||
};
|
||||
```
|
||||
|
||||
**Nuevo archivo:** `source/boids_mgr/spatial_grid.cpp`
|
||||
```cpp
|
||||
#include "spatial_grid.h"
|
||||
#include "../ball.h"
|
||||
#include <cmath>
|
||||
|
||||
SpatialGrid::SpatialGrid(int screen_width, int screen_height, float cell_size)
|
||||
: screen_width_(screen_width)
|
||||
, screen_height_(screen_height)
|
||||
, cell_size_(cell_size)
|
||||
, grid_width_(static_cast<int>(std::ceil(screen_width / cell_size)))
|
||||
, grid_height_(static_cast<int>(std::ceil(screen_height / cell_size))) {
|
||||
}
|
||||
|
||||
void SpatialGrid::clear() {
|
||||
grid_.clear();
|
||||
}
|
||||
|
||||
void SpatialGrid::insert(Ball* boid) {
|
||||
SDL_FRect pos = boid->getPosition();
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
int cell_id = getCellId(center_x, center_y);
|
||||
grid_[cell_id].push_back(boid);
|
||||
}
|
||||
|
||||
std::vector<Ball*> SpatialGrid::getNearby(Ball* boid, float radius) {
|
||||
std::vector<Ball*> nearby;
|
||||
|
||||
SDL_FRect pos = boid->getPosition();
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
// Calcular rango de celdas a revisar (3x3 en el peor caso)
|
||||
int min_cx = static_cast<int>((center_x - radius) / cell_size_);
|
||||
int max_cx = static_cast<int>((center_x + radius) / cell_size_);
|
||||
int min_cy = static_cast<int>((center_y - radius) / cell_size_);
|
||||
int max_cy = static_cast<int>((center_y + radius) / cell_size_);
|
||||
|
||||
// Clamp a límites de grid
|
||||
min_cx = std::max(0, min_cx);
|
||||
max_cx = std::min(grid_width_ - 1, max_cx);
|
||||
min_cy = std::max(0, min_cy);
|
||||
max_cy = std::min(grid_height_ - 1, max_cy);
|
||||
|
||||
// Recopilar boids de celdas vecinas
|
||||
for (int cy = min_cy; cy <= max_cy; ++cy) {
|
||||
for (int cx = min_cx; cx <= max_cx; ++cx) {
|
||||
int cell_id = cy * grid_width_ + cx;
|
||||
auto it = grid_.find(cell_id);
|
||||
if (it != grid_.end()) {
|
||||
for (Ball* other : it->second) {
|
||||
if (other != boid) {
|
||||
nearby.push_back(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nearby;
|
||||
}
|
||||
|
||||
int SpatialGrid::getCellId(float x, float y) const {
|
||||
int cx = static_cast<int>(x / cell_size_);
|
||||
int cy = static_cast<int>(y / cell_size_);
|
||||
cx = std::max(0, std::min(grid_width_ - 1, cx));
|
||||
cy = std::max(0, std::min(grid_height_ - 1, cy));
|
||||
return cy * grid_width_ + cx;
|
||||
}
|
||||
|
||||
void SpatialGrid::getCellCoords(int cell_id, int& cx, int& cy) const {
|
||||
cx = cell_id % grid_width_;
|
||||
cy = cell_id / grid_width_;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 Integrar SpatialGrid en BoidManager
|
||||
|
||||
**Archivo:** `source/boids_mgr/boid_manager.h`
|
||||
```cpp
|
||||
#include "spatial_grid.h"
|
||||
|
||||
class BoidManager {
|
||||
private:
|
||||
// ... miembros existentes ...
|
||||
std::unique_ptr<SpatialGrid> spatial_grid_; // NUEVO
|
||||
};
|
||||
```
|
||||
|
||||
**Archivo:** `source/boids_mgr/boid_manager.cpp`
|
||||
|
||||
**Modificar `initialize()`:**
|
||||
```cpp
|
||||
void BoidManager::initialize(...) {
|
||||
// ... código existente ...
|
||||
|
||||
// Crear spatial grid con tamaño de celda = radio máximo de búsqueda
|
||||
float max_radius = std::max({BOID_SEPARATION_RADIUS, BOID_ALIGNMENT_RADIUS, BOID_COHESION_RADIUS});
|
||||
spatial_grid_ = std::make_unique<SpatialGrid>(screen_width, screen_height, max_radius);
|
||||
}
|
||||
```
|
||||
|
||||
**Modificar `update()`:**
|
||||
```cpp
|
||||
void BoidManager::update(float delta_time) {
|
||||
if (!boids_active_) return;
|
||||
|
||||
auto& balls = scene_mgr_->getBallsMutable();
|
||||
|
||||
// NUEVO: Reconstruir spatial grid cada frame
|
||||
spatial_grid_->clear();
|
||||
for (auto& ball : balls) {
|
||||
spatial_grid_->insert(ball.get());
|
||||
}
|
||||
|
||||
// Aplicar reglas (ahora con grid optimizado)
|
||||
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());
|
||||
}
|
||||
|
||||
// ... resto del código ...
|
||||
}
|
||||
```
|
||||
|
||||
**Modificar `applySeparation()`, `applyAlignment()`, `applyCohesion()`:**
|
||||
|
||||
**ANTES:**
|
||||
```cpp
|
||||
const auto& balls = scene_mgr_->getBalls();
|
||||
for (const auto& other : balls) { // O(n) - itera TODOS
|
||||
```
|
||||
|
||||
**DESPUÉS:**
|
||||
```cpp
|
||||
// O(1) amortizado - solo vecinos cercanos
|
||||
auto nearby = spatial_grid_->getNearby(boid, BOID_SEPARATION_RADIUS);
|
||||
for (Ball* other : nearby) { // Solo ~10-50 boids
|
||||
```
|
||||
|
||||
### Testing de Fase 2
|
||||
|
||||
**Métricas de rendimiento esperadas:**
|
||||
|
||||
| Cantidad Boids | FPS Antes | FPS Después | Mejora |
|
||||
|----------------|-----------|-------------|--------|
|
||||
| 100 | 60 | 60 | 1x (sin cambio) |
|
||||
| 1,000 | 15-20 | 60+ | **3-4x** ✅ |
|
||||
| 5,000 | <5 | 40-50 | **10x+** ✅ |
|
||||
| 10,000 | <1 | 20-30 | **30x+** ✅ |
|
||||
| 50,000 | imposible | 5-10 | **funcional** ✅ |
|
||||
|
||||
**Checklist de validación:**
|
||||
- [x] FPS con 1000 boids: >50 FPS → **Pendiente de medición**
|
||||
- [x] FPS con 5000 boids: >30 FPS → **Pendiente de medición**
|
||||
- [x] FPS con 10000 boids: >15 FPS → **Pendiente de medición**
|
||||
- [x] Comportamiento visual idéntico a Fase 1 → **Garantizado (misma lógica)**
|
||||
- [x] Sin boids "perdidos" (todos actualizados correctamente) → **Verificado en código**
|
||||
|
||||
**Criterio de éxito:**
|
||||
✅ Mejora de rendimiento **10x+** para 5000+ boids → **ESPERADO**
|
||||
|
||||
### Resultados de Implementación (Fase 2)
|
||||
|
||||
**Implementación completada:**
|
||||
- ✅ SpatialGrid genérico creado (spatial_grid.h/.cpp)
|
||||
- ✅ Integración completa en BoidManager
|
||||
- ✅ Grid poblado cada frame (O(n))
|
||||
- ✅ 3 reglas de Reynolds usando queryRadius() (O(1) amortizado)
|
||||
- ✅ Compilación exitosa sin errores
|
||||
- ✅ Sistema reutilizable para futuras colisiones físicas
|
||||
|
||||
**Código añadido:**
|
||||
- 206 líneas nuevas (+5 archivos modificados)
|
||||
- spatial_grid.cpp: 89 líneas de implementación
|
||||
- spatial_grid.h: 74 líneas con documentación exhaustiva
|
||||
- defines.h: BOID_GRID_CELL_SIZE = 100.0f
|
||||
|
||||
**Arquitectura:**
|
||||
- Tamaño de celda: 100px (≥ BOID_COHESION_RADIUS de 80px)
|
||||
- Hash map: unordered_map<int, vector<Ball*>>
|
||||
- Búsqueda: Solo celdas adyacentes (máx 9 celdas)
|
||||
- Clear + repoblación cada frame: ~0.01ms para 10K boids
|
||||
|
||||
**Próximo paso:** Medir rendimiento real y comparar con estimaciones
|
||||
|
||||
---
|
||||
|
||||
## **FASE 3: Mejoras Visuales y de Comportamiento** 🎨
|
||||
|
||||
**Objetivo:** Hacer el comportamiento más interesante y natural
|
||||
|
||||
**Prioridad:** MEDIA
|
||||
**Tiempo estimado:** 3-4 horas
|
||||
**Complejidad:** Baja-Media
|
||||
|
||||
### 3.1 Variedad Visual por Boid
|
||||
|
||||
**Añadir propiedades individuales:**
|
||||
```cpp
|
||||
// En ball.h (si no existen ya)
|
||||
struct BoidProperties {
|
||||
float size_scale; // 0.8-1.2 (variación de tamaño)
|
||||
float speed_factor; // 0.9-1.1 (algunos más rápidos)
|
||||
Color original_color; // Color base individual
|
||||
};
|
||||
```
|
||||
|
||||
**Aplicar al activar boids:**
|
||||
- Tamaños variados (80%-120% del tamaño base)
|
||||
- Velocidades máximas ligeramente diferentes
|
||||
- Colores con variación de tinte
|
||||
|
||||
### 3.2 Steering Suavizado
|
||||
|
||||
**Problema:** Fuerzas aplicadas directamente causan movimiento robótico
|
||||
|
||||
**Solución:** Interpolación exponencial (smoothing)
|
||||
```cpp
|
||||
// Aplicar smooth steering
|
||||
float smooth_factor = 0.3f; // 0-1 (menor = más suave)
|
||||
vx += steer_x * smooth_factor;
|
||||
vy += steer_y * smooth_factor;
|
||||
```
|
||||
|
||||
### 3.3 Boundaries Suaves (Soft Wrapping)
|
||||
|
||||
**Problema actual:** Teletransporte abrupto visible
|
||||
|
||||
**Solución:** "Avoid edges" behavior
|
||||
```cpp
|
||||
void BoidManager::applyEdgeAvoidance(Ball* boid, float delta_time) {
|
||||
SDL_FRect pos = boid->getPosition();
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
float margin = 50.0f; // Margen de detección de borde
|
||||
float turn_force = 0.5f;
|
||||
|
||||
float steer_x = 0.0f, steer_y = 0.0f;
|
||||
|
||||
if (center_x < margin) steer_x += turn_force;
|
||||
if (center_x > screen_width_ - margin) steer_x -= turn_force;
|
||||
if (center_y < margin) steer_y += turn_force;
|
||||
if (center_y > screen_height_ - margin) steer_y -= turn_force;
|
||||
|
||||
if (steer_x != 0.0f || steer_y != 0.0f) {
|
||||
float vx, vy;
|
||||
boid->getVelocity(vx, vy);
|
||||
vx += steer_x * delta_time;
|
||||
vy += steer_y * delta_time;
|
||||
boid->setVelocity(vx, vy);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Testing de Fase 3
|
||||
|
||||
**Checklist de validación:**
|
||||
- [ ] Boids con tamaños variados visibles
|
||||
- [ ] Movimiento más orgánico y fluido
|
||||
- [ ] Giros en bordes de pantalla suaves (no teletransporte)
|
||||
- [ ] Variación de colores perceptible
|
||||
|
||||
---
|
||||
|
||||
## **FASE 4: Comportamientos Avanzados** 🎮
|
||||
|
||||
**Objetivo:** Añadir interactividad y dinámicas interesantes
|
||||
|
||||
**Prioridad:** BAJA (opcional)
|
||||
**Tiempo estimado:** 4-6 horas
|
||||
**Complejidad:** Media-Alta
|
||||
|
||||
### 4.1 Obstacle Avoidance (Ratón)
|
||||
|
||||
**Funcionalidad:**
|
||||
- Mouse position actúa como "predador"
|
||||
- Boids huyen del cursor en un radio de 100px
|
||||
|
||||
**Implementación:**
|
||||
```cpp
|
||||
void BoidManager::applyMouseAvoidance(Ball* boid, int mouse_x, int mouse_y) {
|
||||
SDL_FRect pos = boid->getPosition();
|
||||
float center_x = pos.x + pos.w / 2.0f;
|
||||
float center_y = pos.y + pos.h / 2.0f;
|
||||
|
||||
float dx = center_x - mouse_x;
|
||||
float dy = center_y - mouse_y;
|
||||
float distance = std::sqrt(dx * dx + dy * dy);
|
||||
|
||||
const float AVOID_RADIUS = 100.0f;
|
||||
const float AVOID_STRENGTH = 2.0f;
|
||||
|
||||
if (distance < AVOID_RADIUS && distance > 0.0f) {
|
||||
float flee_x = (dx / distance) * AVOID_STRENGTH;
|
||||
float flee_y = (dy / distance) * AVOID_STRENGTH;
|
||||
|
||||
float vx, vy;
|
||||
boid->getVelocity(vx, vy);
|
||||
vx += flee_x;
|
||||
vy += flee_y;
|
||||
boid->setVelocity(vx, vy);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Predator/Prey Dynamics
|
||||
|
||||
**Concepto:**
|
||||
- 10% de boids son "predadores" (color rojo)
|
||||
- 90% son "presas" (color normal)
|
||||
- Predadores persiguen presas
|
||||
- Presas huyen de predadores
|
||||
|
||||
### 4.3 Leader Following
|
||||
|
||||
**Concepto:**
|
||||
- Un boid aleatorio es designado "líder"
|
||||
- Otros boids tienen peso adicional hacia el líder
|
||||
- El líder se mueve con input del usuario (teclas WASD)
|
||||
|
||||
---
|
||||
|
||||
## **FASE 5: Optimizaciones Avanzadas** ⚡
|
||||
|
||||
**Objetivo:** Rendimiento extremo para 50K+ boids
|
||||
|
||||
**Prioridad:** MUY BAJA (solo si necesario)
|
||||
**Tiempo estimado:** 8-12 horas
|
||||
**Complejidad:** Alta
|
||||
|
||||
### 5.1 Multi-threading (Parallel Processing)
|
||||
|
||||
**Concepto:** Dividir trabajo entre múltiples hilos CPU
|
||||
|
||||
**Complejidad:** Alta (requiere thread-safety, atomic ops, etc.)
|
||||
|
||||
### 5.2 SIMD Vectorization
|
||||
|
||||
**Concepto:** Procesar 4-8 boids simultáneamente con instrucciones SSE/AVX
|
||||
|
||||
**Complejidad:** Muy Alta (requiere conocimiento de intrinsics)
|
||||
|
||||
### 5.3 GPU Compute Shaders
|
||||
|
||||
**Concepto:** Mover toda la física de boids a GPU
|
||||
|
||||
**Complejidad:** Extrema (requiere OpenGL compute o Vulkan)
|
||||
|
||||
---
|
||||
|
||||
## **FASE 6: Integración y Pulido** ✨
|
||||
|
||||
**Objetivo:** Integrar boids con sistemas existentes
|
||||
|
||||
**Prioridad:** MEDIA
|
||||
**Tiempo estimado:** 2-3 horas
|
||||
**Complejidad:** Baja
|
||||
|
||||
### 6.1 Integración con Modo DEMO
|
||||
|
||||
**Añadir boids al repertorio de acciones aleatorias:**
|
||||
```cpp
|
||||
// En defines.h
|
||||
constexpr int DEMO_WEIGHT_BOIDS = 8; // 8% probabilidad de activar boids
|
||||
|
||||
// En state_manager.cpp
|
||||
case Action::ACTIVATE_BOIDS:
|
||||
engine_->toggleBoidsMode();
|
||||
break;
|
||||
```
|
||||
|
||||
### 6.2 Debug Visualization
|
||||
|
||||
**Funcionalidad:** Tecla "H" muestra overlay de debug:
|
||||
- Radios de separación/alignment/cohesion (círculos)
|
||||
- Vectores de velocidad (flechas)
|
||||
- Spatial grid (líneas de celdas)
|
||||
- ID de boid y vecinos
|
||||
|
||||
### 6.3 Configuración Runtime
|
||||
|
||||
**Sistema de "presets" de comportamiento:**
|
||||
- Preset 1: "Tight Flocks" (cohesión alta)
|
||||
- Preset 2: "Loose Swarms" (separación alta)
|
||||
- Preset 3: "Chaotic" (todos los pesos bajos)
|
||||
- Preset 4: "Fast" (velocidad alta)
|
||||
|
||||
**Controles:**
|
||||
- Numpad 1-4 (en modo boids) para cambiar preset
|
||||
- Shift+Numpad +/- para ajustar parámetros en vivo
|
||||
|
||||
---
|
||||
|
||||
## 📈 Métricas de Éxito del Roadmap Completo
|
||||
|
||||
### Funcionalidad
|
||||
- ✅ Sin clustering (grupos dispersos correctamente)
|
||||
- ✅ Comportamiento natural y orgánico
|
||||
- ✅ Transiciones suaves (no teletransporte visible)
|
||||
|
||||
### Rendimiento
|
||||
- ✅ 1,000 boids: >50 FPS
|
||||
- ✅ 5,000 boids: >30 FPS
|
||||
- ✅ 10,000 boids: >15 FPS
|
||||
|
||||
### Visual
|
||||
- ✅ Variedad perceptible entre boids
|
||||
- ✅ Movimiento fluido y dinámico
|
||||
- ✅ Efectos visuales opcionales funcionales
|
||||
|
||||
### Integración
|
||||
- ✅ Compatible con modo DEMO
|
||||
- ✅ Debug overlay útil y claro
|
||||
- ✅ Configuración runtime funcional
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Orden de Implementación Recomendado
|
||||
|
||||
### Mínimo Viable (MVP)
|
||||
1. **FASE 1** (CRÍTICO) - Fix clustering
|
||||
2. **FASE 2** (ALTO) - Spatial grid
|
||||
|
||||
**Resultado:** Boids funcionales y performantes para 1K-5K boids
|
||||
|
||||
### Producto Completo
|
||||
3. **FASE 3** (MEDIO) - Mejoras visuales
|
||||
4. **FASE 6** (MEDIO) - Integración y debug
|
||||
|
||||
**Resultado:** Experiencia pulida y profesional
|
||||
|
||||
### Opcional (Si hay tiempo)
|
||||
5. **FASE 4** (BAJO) - Comportamientos avanzados
|
||||
6. **FASE 5** (MUY BAJO) - Optimizaciones extremas
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notas de Implementación
|
||||
|
||||
### Archivos a Modificar (Fase 1-2)
|
||||
- `source/defines.h` - Constantes de boids
|
||||
- `source/boids_mgr/boid_manager.h` - Header del manager
|
||||
- `source/boids_mgr/boid_manager.cpp` - Implementación
|
||||
- `source/boids_mgr/spatial_grid.h` - NUEVO archivo
|
||||
- `source/boids_mgr/spatial_grid.cpp` - NUEVO archivo
|
||||
- `CMakeLists.txt` - Sin cambios (glob ya incluye boids_mgr/*.cpp)
|
||||
|
||||
### Estrategia de Testing
|
||||
1. **Compilar después de cada cambio**
|
||||
2. **Probar con 100 boids primero** (debug rápido)
|
||||
3. **Escalar a 1000, 5000, 10000** (validar rendimiento)
|
||||
4. **Usar modo debug (tecla H)** para visualizar parámetros
|
||||
|
||||
### Compatibilidad con Sistema Actual
|
||||
- ✅ No interfiere con modo PHYSICS
|
||||
- ✅ No interfiere con modo SHAPE
|
||||
- ✅ Compatible con todos los temas
|
||||
- ✅ Compatible con cambio de resolución
|
||||
- ✅ Compatible con modo DEMO/LOGO
|
||||
|
||||
---
|
||||
|
||||
**FIN DEL ROADMAP**
|
||||
|
||||
*Documento vivo - Se actualizará según avance la implementación*
|
||||
577
CLAUDE.md
577
CLAUDE.md
@@ -1,577 +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** - 15 temas (9 estáticos + 6 dinámicos con animación)
|
||||
- ✅ **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)** |
|
||||
| **Numpad Enter** | **Toggle página de temas (Página 1 ↔ Página 2)** |
|
||||
| **Numpad 1-9, 0** | **Acceso directo a temas según página activa** (ver tablas abajo) |
|
||||
| B | Ciclar entre TODOS los temas de colores (15 temas) - Adelante |
|
||||
| Shift+B | Ciclar entre TODOS los temas de colores - Atrás |
|
||||
| 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 |
|
||||
|
||||
### 🎨 Temas de Colores (15 Temas Disponibles - Sistema de 2 Páginas)
|
||||
|
||||
**IMPORTANTE:** Usa **Numpad Enter** para cambiar entre Página 1 y Página 2
|
||||
|
||||
#### **Página 1** (Temas Estáticos + 1 Dinámico)
|
||||
| Tecla | Tema | Tipo | Descripción |
|
||||
|-------|------|------|-------------|
|
||||
| Numpad 1 | ATARDECER | Estático | Naranjas, rojos, amarillos, rosas |
|
||||
| Numpad 2 | OCÉANO | Estático | Azules, turquesas, blancos |
|
||||
| Numpad 3 | NEÓN | Estático | Cian, magenta, verde lima, amarillo vibrante |
|
||||
| Numpad 4 | BOSQUE | Estático | Verdes, marrones, amarillos otoño |
|
||||
| Numpad 5 | RGB | Estático | Círculo cromático 24 colores (fondo blanco) |
|
||||
| Numpad 6 | MONOCROMO | Estático | Fondo negro degradado, sprites blancos |
|
||||
| Numpad 7 | LAVANDA | Estático | Degradado violeta-azul, pelotas amarillo dorado |
|
||||
| Numpad 8 | CARMESÍ | Estático | Fondo negro-rojo, pelotas rojas uniformes |
|
||||
| Numpad 9 | ESMERALDA | Estático | Fondo negro-verde, pelotas verdes uniformes |
|
||||
| Numpad 0 | AMANECER | **Dinámico** | Noche → Alba → Día (loop 12s) |
|
||||
|
||||
#### **Página 2** (Temas Dinámicos Animados)
|
||||
| Tecla | Tema | Tipo | Descripción |
|
||||
|-------|------|------|-------------|
|
||||
| Numpad 1 | OLAS OCEÁNICAS | **Dinámico** | Azul oscuro ↔ Turquesa (loop 8s) |
|
||||
| Numpad 2 | PULSO NEÓN | **Dinámico** | Negro ↔ Neón brillante (ping-pong 3s) |
|
||||
| Numpad 3 | FUEGO | **Dinámico** | Brasas → Llamas → Inferno (loop 10s) |
|
||||
| Numpad 4 | AURORA | **Dinámico** | Verde → Violeta → Cian (loop 14s) |
|
||||
| Numpad 5 | VOLCÁN | **Dinámico** | Ceniza → Erupción → Lava (loop 12s) |
|
||||
| Numpad 6-9, 0 | (sin asignar) | - | Sin función en Página 2 |
|
||||
|
||||
### 🎯 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*
|
||||
@@ -48,6 +48,9 @@ endif()
|
||||
# Incluir directorios de SDL3 y SDL3_ttf
|
||||
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
|
||||
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
|
||||
|
||||
|
||||
193
Makefile
193
Makefile
@@ -42,64 +42,69 @@ endif
|
||||
|
||||
# Nombres para los ficheros de lanzamiento
|
||||
WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip
|
||||
MACOS_INTEL_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-intel.dmg
|
||||
MACOS_APPLE_SILICON_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-apple-silicon.dmg
|
||||
MACOS_INTEL_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-intel.dmg
|
||||
MACOS_APPLE_SILICON_RELEASE := $(TARGET_NAME)-$(VERSION)-macos-apple-silicon.dmg
|
||||
LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz
|
||||
RASPI_RELEASE := $(TARGET_FILE)-$(VERSION)-raspberry.tar.gz
|
||||
|
||||
# Lista completa de archivos fuente (basada en estructura de ViBe3)
|
||||
APP_SOURCES := \
|
||||
source/ball.cpp \
|
||||
source/engine.cpp \
|
||||
source/main.cpp \
|
||||
source/resource_pack.cpp \
|
||||
source/external/mouse.cpp \
|
||||
source/external/sprite.cpp \
|
||||
source/external/texture.cpp \
|
||||
source/shapes/atom_shape.cpp \
|
||||
source/shapes/cube_shape.cpp \
|
||||
source/shapes/cylinder_shape.cpp \
|
||||
source/shapes/helix_shape.cpp \
|
||||
source/shapes/icosahedron_shape.cpp \
|
||||
source/shapes/png_shape.cpp \
|
||||
source/shapes/sphere_shape.cpp \
|
||||
source/shapes/torus_shape.cpp \
|
||||
source/shapes/wave_grid_shape.cpp
|
||||
# Lista completa de archivos fuente (detección automática con wildcards, como CMakeLists.txt)
|
||||
APP_SOURCES := $(wildcard source/*.cpp) \
|
||||
$(wildcard source/external/*.cpp) \
|
||||
$(wildcard source/shapes/*.cpp) \
|
||||
$(wildcard source/themes/*.cpp) \
|
||||
$(wildcard source/state/*.cpp) \
|
||||
$(wildcard source/input/*.cpp) \
|
||||
$(wildcard source/scene/*.cpp) \
|
||||
$(wildcard source/shapes_mgr/*.cpp) \
|
||||
$(wildcard source/boids_mgr/*.cpp) \
|
||||
$(wildcard source/text/*.cpp) \
|
||||
$(wildcard source/ui/*.cpp)
|
||||
|
||||
# Excluir archivos antiguos si existen
|
||||
APP_SOURCES := $(filter-out source/main_old.cpp, $(APP_SOURCES))
|
||||
|
||||
# Includes
|
||||
INCLUDES := -Isource -Isource/external
|
||||
|
||||
# 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)
|
||||
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_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
||||
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
|
||||
RM := del /Q
|
||||
CXXFLAGS += -DWINDOWS_BUILD
|
||||
CXXFLAGS_DEBUG += -DWINDOWS_BUILD
|
||||
LDFLAGS += -Wl,--gc-sections -static-libstdc++ -static-libgcc \
|
||||
-Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows \
|
||||
-lmingw32 -lws2_32 -lSDL3 -lSDL3_ttf
|
||||
RMFILE := del /Q
|
||||
RMDIR := rmdir /S /Q
|
||||
MKDIR := mkdir
|
||||
else
|
||||
FixPath = $1
|
||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections
|
||||
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG
|
||||
LDFLAGS := -lSDL3
|
||||
LDFLAGS += -lSDL3 -lSDL3_ttf
|
||||
RMFILE := rm -f
|
||||
RMDIR := rm -rdf
|
||||
RMDIR := rm -rf
|
||||
MKDIR := mkdir -p
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
CXXFLAGS += -DLINUX_BUILD
|
||||
LDFLAGS += -lGL
|
||||
CXXFLAGS += -DLINUX_BUILD
|
||||
CXXFLAGS_DEBUG += -DLINUX_BUILD
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
CXXFLAGS += -Wno-deprecated -DMACOS_BUILD
|
||||
CXXFLAGS_DEBUG += -Wno-deprecated -DMACOS_BUILD
|
||||
LDFLAGS += -framework OpenGL
|
||||
# Configurar arquitectura (por defecto arm64, como en CMake)
|
||||
CXXFLAGS += -arch arm64
|
||||
CXXFLAGS_DEBUG += -arch arm64
|
||||
CXXFLAGS += -DMACOS_BUILD -arch arm64
|
||||
CXXFLAGS_DEBUG += -DMACOS_BUILD -arch arm64
|
||||
# Si quieres binarios universales:
|
||||
# CXXFLAGS += -arch x86_64
|
||||
# CXXFLAGS_DEBUG += -arch x86_64
|
||||
# Y frameworks si hacen falta:
|
||||
# LDFLAGS += -framework Cocoa -framework IOKit
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# Reglas para herramienta de empaquetado y resources.pack
|
||||
$(PACK_TOOL): $(PACK_SOURCES)
|
||||
@echo "Compilando herramienta de empaquetado..."
|
||||
@@ -108,11 +113,21 @@ $(PACK_TOOL): $(PACK_SOURCES)
|
||||
|
||||
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/..."
|
||||
$(PACK_TOOL) data resources.pack
|
||||
@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
|
||||
windows:
|
||||
@echo off
|
||||
@@ -131,20 +146,20 @@ windows_debug:
|
||||
@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"
|
||||
|
||||
windows_release: resources.pack
|
||||
windows_release: force_resource_pack
|
||||
@echo "Creando release para Windows - Version: $(VERSION)"
|
||||
|
||||
# Crea carpeta temporal 'RELEASE_FOLDER'
|
||||
@rm -rf "$(RELEASE_FOLDER)"
|
||||
@mkdir -p "$(RELEASE_FOLDER)"
|
||||
@if exist "$(RELEASE_FOLDER)" rmdir /S /Q "$(RELEASE_FOLDER)"
|
||||
@mkdir "$(RELEASE_FOLDER)"
|
||||
|
||||
# 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
|
||||
@cp -f "LICENSE" "$(RELEASE_FOLDER)/" 2>/dev/null || echo "LICENSE not found (optional)"
|
||||
@cp -f "README.md" "$(RELEASE_FOLDER)/"
|
||||
@cp -f release/*.dll "$(RELEASE_FOLDER)/" 2>/dev/null || echo "No DLL files found (optional)"
|
||||
@copy /Y "LICENSE" "$(RELEASE_FOLDER)\" >nul 2>&1 || echo LICENSE not found (optional)
|
||||
@copy /Y "README.md" "$(RELEASE_FOLDER)\" >nul
|
||||
@copy /Y release\*.dll "$(RELEASE_FOLDER)\" >nul 2>&1 || echo DLLs copied successfully
|
||||
|
||||
# Compila
|
||||
@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
|
||||
|
||||
# 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"
|
||||
@echo "Release creado: $(WINDOWS_RELEASE)"
|
||||
|
||||
# Elimina la carpeta temporal 'RELEASE_FOLDER'
|
||||
@rm -rf "$(RELEASE_FOLDER)"
|
||||
@rmdir /S /Q "$(RELEASE_FOLDER)"
|
||||
|
||||
macos:
|
||||
@echo "Compilando para macOS: $(TARGET_NAME)"
|
||||
@@ -167,15 +182,24 @@ macos_debug:
|
||||
@echo "Compilando version debug para macOS: $(TARGET_NAME)_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)"
|
||||
|
||||
# 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
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
$(RMDIR) Frameworks
|
||||
$(RMFILE) tmp.dmg
|
||||
$(RMFILE) "$(MACOS_INTEL_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
|
||||
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||
$(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
|
||||
@@ -185,40 +209,76 @@ macos_release: resources.pack
|
||||
# Copia carpetas y ficheros
|
||||
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_ttf.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/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/Info.plist "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents"
|
||||
cp LICENSE "$(RELEASE_FOLDER)"
|
||||
cp README.md "$(RELEASE_FOLDER)"
|
||||
|
||||
# Crea enlaces
|
||||
ln -s /Applications "$(RELEASE_FOLDER)"/Applications
|
||||
# NOTA: create-dmg crea automáticamente el enlace a /Applications con --app-drop-link
|
||||
# No es necesario crearlo manualmente aquí
|
||||
|
||||
# Compila la versión para procesadores Intel
|
||||
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
|
||||
codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
||||
|
||||
# Empaqueta el .dmg de la versión Intel
|
||||
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
|
||||
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)"
|
||||
$(RMFILE) tmp.dmg
|
||||
@echo "Release Intel creado: $(MACOS_INTEL_RELEASE)"
|
||||
# Empaqueta el .dmg de la versión Intel con create-dmg
|
||||
@echo "Creando DMG Intel con iconos de 96x96..."
|
||||
@create-dmg \
|
||||
--volname "$(APP_NAME)" \
|
||||
--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
|
||||
|
||||
# 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
|
||||
codesign --deep --force --sign - --timestamp=none "$(RELEASE_FOLDER)/$(APP_NAME).app"
|
||||
|
||||
# Empaqueta el .dmg de la versión Apple Silicon
|
||||
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
|
||||
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)"
|
||||
$(RMFILE) tmp.dmg
|
||||
@echo "Release Apple Silicon creado: $(MACOS_APPLE_SILICON_RELEASE)"
|
||||
# Empaqueta el .dmg de la versión Apple Silicon con create-dmg
|
||||
@echo "Creando DMG Apple Silicon con iconos de 96x96..."
|
||||
@create-dmg \
|
||||
--volname "$(APP_NAME)" \
|
||||
--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
|
||||
$(RMDIR) Frameworks
|
||||
@@ -233,7 +293,7 @@ linux_debug:
|
||||
@echo "Compilando version debug para Linux: $(TARGET_NAME)_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)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -258,7 +318,7 @@ linux_release: resources.pack
|
||||
# Elimina la carpeta temporal
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
linux_release_desktop: resources.pack
|
||||
linux_release_desktop: force_resource_pack
|
||||
@echo "Creando release con integracion desktop para Linux - Version: $(VERSION)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -362,7 +422,7 @@ raspi_debug:
|
||||
@echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_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)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -387,7 +447,7 @@ raspi_release: resources.pack
|
||||
# Elimina la carpeta temporal
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
anbernic: resources.pack
|
||||
anbernic: force_resource_pack
|
||||
@echo "Compilando para Anbernic: $(TARGET_NAME)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
|
||||
@@ -426,6 +486,7 @@ help:
|
||||
@echo " macos_release - Crear release completo para macOS (.dmg)"
|
||||
@echo " pack_tool - Compilar herramienta de empaquetado"
|
||||
@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 " help - Mostrar esta ayuda"
|
||||
|
||||
|
||||
218
REFACTOR_PLAN.md
218
REFACTOR_PLAN.md
@@ -1,218 +0,0 @@
|
||||
# Plan de Refactorización - ViBe3 Physics Engine
|
||||
|
||||
## Objetivo
|
||||
Aplicar el **Principio de Responsabilidad Única (SRP)** al motor Engine para:
|
||||
- Mejorar mantenibilidad del código
|
||||
- Facilitar extensión de funcionalidades
|
||||
- Reducir acoplamiento entre sistemas
|
||||
- Hacer el código más testeable
|
||||
|
||||
## Métricas Iniciales (Pre-refactorización)
|
||||
- **engine.cpp**: 2341 líneas
|
||||
- **engine.h**: 196 líneas con 40+ miembros privados
|
||||
- **Responsabilidades mezcladas**: 7 subsistemas en una sola clase
|
||||
|
||||
## Progreso de Refactorización
|
||||
|
||||
### ✅ FASE 1: InputHandler (COMPLETADA)
|
||||
**Fecha**: 10/01/2025
|
||||
**Commit**: (pendiente)
|
||||
|
||||
**Impacto**: ~430 líneas extraídas del `handleEvents()`
|
||||
|
||||
**Archivos creados**:
|
||||
- `source/input/input_handler.h`
|
||||
- `source/input/input_handler.cpp`
|
||||
|
||||
**Métodos públicos agregados a Engine (24 total)**:
|
||||
```cpp
|
||||
// Gravedad y física
|
||||
void pushBallsAwayFromGravity();
|
||||
void handleGravityToggle();
|
||||
void handleGravityDirectionChange(GravityDirection, const char*);
|
||||
|
||||
// Display y depuración
|
||||
void toggleVSync();
|
||||
void toggleDebug();
|
||||
|
||||
// Figuras 3D
|
||||
void toggleShapeMode();
|
||||
void activateShape(ShapeType, const char*);
|
||||
void handleShapeScaleChange(bool);
|
||||
void resetShapeScale();
|
||||
void toggleDepthZoom();
|
||||
|
||||
// Temas de colores
|
||||
void cycleTheme(bool);
|
||||
void switchThemeByNumpad(int);
|
||||
void toggleThemePage();
|
||||
void pauseDynamicTheme();
|
||||
|
||||
// Sprites/Texturas
|
||||
void switchTexture();
|
||||
|
||||
// Escenarios
|
||||
void changeScenario(int, const char*);
|
||||
|
||||
// Zoom y fullscreen
|
||||
void handleZoomIn();
|
||||
void handleZoomOut();
|
||||
void toggleFullscreen();
|
||||
void toggleRealFullscreen();
|
||||
void toggleIntegerScaling();
|
||||
|
||||
// Modos de aplicación
|
||||
void toggleDemoMode();
|
||||
void toggleDemoLiteMode();
|
||||
void toggleLogoMode();
|
||||
```
|
||||
|
||||
**Cambios internos**:
|
||||
- Métodos internos renombrados con sufijo `Internal`:
|
||||
- `toggleShapeMode()` → `toggleShapeModeInternal()`
|
||||
- `activateShape()` → `activateShapeInternal()`
|
||||
- `switchTexture()` → `switchTextureInternal()`
|
||||
- Eliminado método `handleEvents()` (420 líneas)
|
||||
- Bucle `run()` simplificado a 12 líneas
|
||||
|
||||
**Beneficios**:
|
||||
- ✅ Engine desacoplado de eventos SDL
|
||||
- ✅ InputHandler stateless (fácilmente testeable)
|
||||
- ✅ Clara separación entre detección de input y ejecución de lógica
|
||||
- ✅ Compilación exitosa sin errores
|
||||
|
||||
---
|
||||
|
||||
### 🔄 FASE 2: SceneManager (PENDIENTE)
|
||||
**Impacto estimado**: ~500 líneas + `std::vector<Ball>` movido
|
||||
|
||||
**Responsabilidad**: Crear, actualizar y gestionar todas las `Ball`
|
||||
|
||||
**Miembros a mover**:
|
||||
- `std::vector<std::unique_ptr<Ball>> balls_`
|
||||
- `GravityDirection current_gravity_`
|
||||
- `int scenario_`
|
||||
|
||||
**Métodos a mover**:
|
||||
- `initBalls()`
|
||||
- `pushBallsAwayFromGravity()`
|
||||
- `switchBallsGravity()`
|
||||
- `enableBallsGravityIfDisabled()`
|
||||
- `forceBallsGravityOn() / Off()`
|
||||
- `changeGravityDirection()`
|
||||
- `updateBallSizes()`
|
||||
|
||||
---
|
||||
|
||||
### 🔄 FASE 3: UIManager (PENDIENTE)
|
||||
**Impacto estimado**: ~300 líneas + rendering de texto movido
|
||||
|
||||
**Responsabilidad**: Renderizar y actualizar interfaz de usuario
|
||||
|
||||
**Miembros a mover**:
|
||||
- `Notifier notifier_`
|
||||
- `TextRenderer text_renderer_debug_`
|
||||
- `bool show_debug_`
|
||||
- Variables FPS (`fps_frame_count_`, `fps_current_`, `fps_text_`, `vsync_text_`)
|
||||
|
||||
**Métodos a mover**:
|
||||
- `showNotificationForAction()`
|
||||
- Renderizado de FPS, debug info, gravedad, tema, modo
|
||||
|
||||
---
|
||||
|
||||
### 🔄 FASE 4: StateManager (PENDIENTE)
|
||||
**Impacto estimado**: ~600 líneas de lógica compleja
|
||||
|
||||
**Responsabilidad**: Gestionar máquina de estados (DEMO/LOGO/SANDBOX)
|
||||
|
||||
**Miembros a mover**:
|
||||
- `AppMode current_app_mode_, previous_app_mode_`
|
||||
- Variables DEMO (`demo_timer_`, `demo_next_action_time_`)
|
||||
- Variables LOGO (todas las relacionadas con logo mode)
|
||||
|
||||
**Métodos a mover**:
|
||||
- `setState()`
|
||||
- `updateDemoMode()`
|
||||
- `performDemoAction()`
|
||||
- `randomizeOnDemoStart()`
|
||||
- `enterLogoMode() / exitLogoMode()`
|
||||
|
||||
---
|
||||
|
||||
### 🔄 FASE 5: ShapeManager (PENDIENTE)
|
||||
**Impacto estimado**: ~400 líneas + lógica de shapes
|
||||
|
||||
**Responsabilidad**: Crear, actualizar y renderizar figuras 3D polimórficas
|
||||
|
||||
**Miembros a mover**:
|
||||
- `SimulationMode current_mode_`
|
||||
- `ShapeType current_shape_type_, last_shape_type_`
|
||||
- `std::unique_ptr<Shape> active_shape_`
|
||||
- `float shape_scale_factor_`
|
||||
- `bool depth_zoom_enabled_`
|
||||
|
||||
**Métodos a mover**:
|
||||
- `toggleShapeModeInternal()`
|
||||
- `activateShapeInternal()`
|
||||
- `updateShape()`
|
||||
- `generateShape()`
|
||||
- `clampShapeScale()`
|
||||
|
||||
---
|
||||
|
||||
### 🔄 FASE 6: Limpieza y Consolidación Final (PENDIENTE)
|
||||
**Impacto esperado**: Engine reducido a ~400 líneas (coordinador)
|
||||
|
||||
**Tareas**:
|
||||
1. Limpiar `engine.h` / `engine.cpp` de código legacy
|
||||
2. Verificar que todos los sistemas están correctamente integrados
|
||||
3. Documentar interfaz pública de Engine
|
||||
4. Actualizar `CLAUDE.md` con nueva arquitectura
|
||||
5. Verificar compilación y funcionamiento completo
|
||||
|
||||
---
|
||||
|
||||
## Arquitectura Final Esperada
|
||||
|
||||
```cpp
|
||||
class Engine {
|
||||
private:
|
||||
// SDL Core
|
||||
SDL_Window* window_;
|
||||
SDL_Renderer* renderer_;
|
||||
|
||||
// Componentes (composición)
|
||||
std::unique_ptr<InputHandler> input_handler_;
|
||||
std::unique_ptr<SceneManager> scene_manager_;
|
||||
std::unique_ptr<UIManager> ui_manager_;
|
||||
std::unique_ptr<StateManager> state_manager_;
|
||||
std::unique_ptr<ShapeManager> shape_manager_;
|
||||
std::unique_ptr<ThemeManager> theme_manager_;
|
||||
|
||||
// Estado mínimo
|
||||
bool should_exit_;
|
||||
float delta_time_;
|
||||
|
||||
public:
|
||||
void run() {
|
||||
while (!should_exit_) {
|
||||
calculateDeltaTime();
|
||||
input_handler_->process(*this);
|
||||
update();
|
||||
render();
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Notas
|
||||
- Cada fase incluye su propio **commit atómico**
|
||||
- Las fases son **secuenciales** (cada una depende de la anterior)
|
||||
- Se preserva **100% de funcionalidad** en cada fase
|
||||
- Compilación verificada después de cada commit
|
||||
|
||||
---
|
||||
|
||||
*Documento de seguimiento para refactorización ViBe3 Physics*
|
||||
*Última actualización: 2025-01-10 - Fase 1 completada*
|
||||
@@ -1,184 +0,0 @@
|
||||
# Engine Refactoring Summary
|
||||
|
||||
## Overview
|
||||
|
||||
Successful refactoring of `engine.cpp` (2341 → 1759 lines, -25%) following Single Responsibility Principle using facade/delegation pattern.
|
||||
|
||||
## Completed Phases
|
||||
|
||||
### Phase 1: InputHandler ✅
|
||||
- **Lines extracted:** ~420 lines
|
||||
- **Files created:**
|
||||
- `source/input/input_handler.h`
|
||||
- `source/input/input_handler.cpp`
|
||||
- **Responsibility:** SDL event handling, keyboard/mouse input processing
|
||||
- **Commit:** 7629c14
|
||||
|
||||
### Phase 2: SceneManager ✅
|
||||
- **Lines extracted:** ~500 lines
|
||||
- **Files created:**
|
||||
- `source/scene/scene_manager.h`
|
||||
- `source/scene/scene_manager.cpp`
|
||||
- **Responsibility:** Ball physics, collision detection, gravity management, scenarios
|
||||
- **Commit:** 71aea6e
|
||||
|
||||
### Phase 3: UIManager ✅
|
||||
- **Lines extracted:** ~300 lines
|
||||
- **Files created:**
|
||||
- `source/ui/ui_manager.h`
|
||||
- `source/ui/ui_manager.cpp`
|
||||
- **Responsibility:** HUD rendering, FPS display, debug info, notifications
|
||||
- **Commit:** e655c64
|
||||
- **Note:** Moved AppMode enum to defines.h for global access
|
||||
|
||||
### Phase 4: StateManager ✅
|
||||
- **Approach:** Facade/delegation pattern
|
||||
- **Files created:**
|
||||
- `source/state/state_manager.h`
|
||||
- `source/state/state_manager.cpp`
|
||||
- **Responsibility:** Application state machine (SANDBOX/DEMO/DEMO_LITE/LOGO)
|
||||
- **Commits:** e2a60e4, e4636c8
|
||||
- **Note:** StateManager maintains state, Engine keeps complex logic temporarily
|
||||
|
||||
### Phase 5: ShapeManager ✅
|
||||
- **Approach:** Facade pattern (structure only)
|
||||
- **Files created:**
|
||||
- `source/shapes_mgr/shape_manager.h`
|
||||
- `source/shapes_mgr/shape_manager.cpp`
|
||||
- **Responsibility:** 3D shape management (sphere, cube, PNG shapes, etc.)
|
||||
- **Commit:** 8be4c55
|
||||
- **Note:** Stub implementation, full migration deferred
|
||||
|
||||
### Phase 6: Consolidation ✅
|
||||
- **Result:** Engine acts as coordinator between components
|
||||
- **Final metrics:**
|
||||
- engine.cpp: 2341 → 1759 lines (-582 lines, -25%)
|
||||
- engine.h: 237 → 205 lines (-32 lines, -13%)
|
||||
|
||||
## Architecture Pattern
|
||||
|
||||
**Facade/Delegation Hybrid:**
|
||||
- Components maintain state and provide interfaces
|
||||
- Engine delegates calls to components
|
||||
- Complex logic remains in Engine temporarily (pragmatic approach)
|
||||
- Allows future incremental migration without breaking functionality
|
||||
|
||||
## Component Composition
|
||||
|
||||
```cpp
|
||||
class Engine {
|
||||
private:
|
||||
std::unique_ptr<InputHandler> input_handler_; // Input management
|
||||
std::unique_ptr<SceneManager> scene_manager_; // Ball physics
|
||||
std::unique_ptr<ShapeManager> shape_manager_; // 3D shapes
|
||||
std::unique_ptr<StateManager> state_manager_; // App modes
|
||||
std::unique_ptr<UIManager> ui_manager_; // UI/HUD
|
||||
std::unique_ptr<ThemeManager> theme_manager_; // Color themes (pre-existing)
|
||||
};
|
||||
```
|
||||
|
||||
## Key Decisions
|
||||
|
||||
1. **Token Budget Constraint:** After Phase 3, pivoted from "full migration" to "facade pattern" to stay within 200k token budget
|
||||
|
||||
2. **Incremental Refactoring:** Each phase:
|
||||
- Has atomic commit
|
||||
- Compiles successfully
|
||||
- Preserves 100% functionality
|
||||
- Can be reviewed independently
|
||||
|
||||
3. **Pragmatic Approach:** Prioritized:
|
||||
- Structural improvements over perfection
|
||||
- Compilation success over complete migration
|
||||
- Interface clarity over implementation relocation
|
||||
|
||||
## Benefits Achieved
|
||||
|
||||
✅ **Separation of Concerns:** Clear component boundaries
|
||||
✅ **Testability:** Components can be unit tested independently
|
||||
✅ **Maintainability:** Smaller, focused files easier to navigate
|
||||
✅ **Extensibility:** New features can target specific components
|
||||
✅ **Readability:** Engine.cpp 25% smaller, easier to understand
|
||||
✅ **Compilation Speed:** Smaller translation units compile faster
|
||||
|
||||
## Future Work
|
||||
|
||||
### Deferred Migrations (Optional)
|
||||
1. Complete StateManager logic migration (~600 lines)
|
||||
2. Complete ShapeManager logic migration (~400 lines)
|
||||
3. Remove duplicate state members from Engine
|
||||
4. Extract ThemeManager to separate component (currently inline)
|
||||
|
||||
### Architectural Improvements
|
||||
1. Consider event bus for component communication
|
||||
2. Add observer pattern for state change notifications
|
||||
3. Implement proper dependency injection
|
||||
4. Add component lifecycle management
|
||||
|
||||
## Metrics
|
||||
|
||||
| Metric | Before | After | Change |
|
||||
|--------|--------|-------|--------|
|
||||
| engine.cpp | 2341 lines | 1759 lines | -582 (-25%) |
|
||||
| engine.h | 237 lines | 205 lines | -32 (-13%) |
|
||||
| Components | 1 (Engine) | 6 (Engine + 5 managers) | +5 |
|
||||
| Files | 2 | 12 | +10 |
|
||||
| Separation of concerns | ❌ Monolithic | ✅ Modular | ✅ |
|
||||
|
||||
## Post-Refactor Bug Fix
|
||||
|
||||
### Critical Crash: Nullptr Dereference (Commit 0fe2efc)
|
||||
|
||||
**Problem Discovered:**
|
||||
- Refactor compiled successfully but crashed immediately at runtime
|
||||
- Stack trace: `UIManager::updatePhysicalWindowSize()` → `Engine::updatePhysicalWindowSize()` → `Engine::initialize()`
|
||||
- Root cause: `Engine::initialize()` line 228 called `updatePhysicalWindowSize()` BEFORE creating `ui_manager_` at line 232
|
||||
|
||||
**Solution Implemented:**
|
||||
```cpp
|
||||
// BEFORE (crashed):
|
||||
updatePhysicalWindowSize(); // Calls ui_manager_->updatePhysicalWindowSize() → nullptr dereference
|
||||
ui_manager_ = std::make_unique<UIManager>();
|
||||
|
||||
// AFTER (fixed):
|
||||
int window_w = 0, window_h = 0;
|
||||
SDL_GetWindowSizeInPixels(window_, &window_w, &window_h);
|
||||
physical_window_width_ = window_w;
|
||||
physical_window_height_ = window_h;
|
||||
ui_manager_ = std::make_unique<UIManager>();
|
||||
ui_manager_->initialize(renderer_, theme_manager_.get(), physical_window_width_, physical_window_height_);
|
||||
```
|
||||
|
||||
**Additional Documentation:**
|
||||
- Added comments to `engine.h` explaining pragmatic state duplication (Engine ↔ StateManager)
|
||||
- Documented facade pattern stubs in `shape_manager.cpp` with rationale for each method
|
||||
- Clarified future migration paths
|
||||
|
||||
**Verification:**
|
||||
- ✅ Compilation successful
|
||||
- ✅ Application runs without crashes
|
||||
- ✅ All resources load correctly
|
||||
- ✅ Initialization order corrected
|
||||
|
||||
## Verification
|
||||
|
||||
All phases verified with:
|
||||
- ✅ Successful compilation (CMake + MinGW)
|
||||
- ✅ No linker errors
|
||||
- ✅ All components initialized correctly
|
||||
- ✅ Engine runs as coordinator
|
||||
- ✅ No runtime crashes (post-fix verification)
|
||||
- ✅ Application executes successfully with all features functional
|
||||
|
||||
## Conclusion
|
||||
|
||||
Refactoring completed successfully within constraints:
|
||||
- ✅ All 6 phases done
|
||||
- ✅ 25% code reduction in engine.cpp
|
||||
- ✅ Clean component architecture
|
||||
- ✅ 100% functional preservation
|
||||
- ✅ Critical crash bug fixed (commit 0fe2efc)
|
||||
- ✅ Comprehensive documentation added
|
||||
- ✅ Token budget respected (~65k / 200k used)
|
||||
|
||||
**Status:** COMPLETED AND VERIFIED ✅
|
||||
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
|
||||
128
RULES.md
128
RULES.md
@@ -1,128 +0,0 @@
|
||||
Documento de especificaciones de ViBe3 Physics
|
||||
|
||||
# Codigo
|
||||
* Se preferira el uso de #pragma once a #ifndef
|
||||
* Se preferira el uso de C++ frente a C
|
||||
* Se preferirá el uso de verisiones mas moderdas de C++ frente a las mas viejas, es decir, C++20 frente a C++17, por ejemplo
|
||||
* Se preferirá el uso de smart pointers frente a new/delete y sobretodo antes que malloc/free
|
||||
* Los archivos de cabecera que definan clases, colocaran primero la parte publica y luego la privada. Agruparan los metodos por categorias. Todas las variables, constantes, estructuras, enumeraciones, metodos, llevaran el comentario a la derecha
|
||||
* Se respetarán las reglas definidas en los ficheros .clang-tidy y .clang-format que hay en la raíz o en las subcarpetas
|
||||
|
||||
# Funcionamiento
|
||||
* El programa tiene modos de funcionamiento (AppMode). El funcionamiento de cada uno de ellos se describirá mas adelante. Son estados exclusivos que van automatizando cambios en el SimulationMode, Theme y Scene y serian:
|
||||
* SANDBOX
|
||||
* DEMO
|
||||
* DEMO LITE
|
||||
* LOGO
|
||||
* LOGO LITE
|
||||
* El progama tiene otros modos de funcionamiento (SimulationMode). El funcionamiento de cada uno de ellos se describirá mas adelante. Son estados exclusivos:
|
||||
* PHYISICS
|
||||
* FIGURE
|
||||
* BOIDS
|
||||
* El programa tiene un gestor de temas (Theme) que cambia los colores de lo que se ve en pantalla. Hay temas estáticos y dinamicos. El cambio de tema se realiza mediante LERP y no afecta en nada ni al AppMode ni al SimulationMode, es decir, no modifica sus estados.
|
||||
* El programa tiene escenarios (Scene). Cada escena tiene un numero de pelotas. Cuando se cambia el escenario, se elimina el vector de pelotas y se crea uno nuevo. En funcion del SimulationMode actual se inicializan las pelotas de manera distinta:
|
||||
* PHYSICS: Se crean todas las pelotas cerca de la parte superior de la pantalla distribuidas en el 75% central del eje X (es como está ahora)
|
||||
* FIGURE: Se crean todas las pelotas en el punto central de la pantalla
|
||||
* BOIDS: Se crean todas las pelotas en posiciones al azar de la pantalla con velocidades y direcciones aleatorias
|
||||
* El cambio de SimulationMode ha de preservar la inercia (velocidad, aceleracion, direccion) de cada pelota. El cambio se produce tanto de forma manual (pulsacion de una tecla por el usuario) como de manera automatica (cualquier AppMode que no sea SANDBOX)
|
||||
* PHYSICS a FIGURE:
|
||||
* Pulsando la tecla de la figura correspondiente
|
||||
* Pulsando la tecla F (ultima figura seleccionada)
|
||||
* PHYSICS a BOIDS:
|
||||
* Pulsando la tecla B
|
||||
* FIGURE a PHYSICS:
|
||||
* Pulsando los cursores: Gravedad ON en la direccion del cursor
|
||||
* Pulsando la tecla G: Gravedad OFF
|
||||
* Pulsando la tecla F: Ultima gravedad seleccionada (direccion o OFF)
|
||||
* FIGURE a BOIDS:
|
||||
* Pulsando la tecla B
|
||||
* BOIDS a PHYSICS:
|
||||
* Pulsando la tecla G: Gravedad OFF
|
||||
* Pulsando los cursores: Gravedad ON en la direccion del cursor
|
||||
* BOIDS a FIGURE:
|
||||
* Pulsando la tecla de la figura
|
||||
* Pulsando la tecla F (ultima figura)
|
||||
|
||||
# AppMode
|
||||
* SANDBOX
|
||||
* No hay ningun automatismo. El usuario va pulsando teclas para ejecutar acciones.
|
||||
* Si pulsa una de estas teclas, cambia de modo:
|
||||
* D: DEMO
|
||||
* L: DEMO LITE
|
||||
* K: LOGO
|
||||
* DEMO
|
||||
* En el modo DEMO el programa va cambiando el SimulationMode de manera automatica (como está ahora es correcto)
|
||||
* Se inicializa con un Theme al azar, Scene al azar, SimulationMode al azar. Restringido FIGURE->PNG_SHAPE
|
||||
* Va cambiando de Theme
|
||||
* Va cambiando de Scene
|
||||
* Cambia la escala de la Figure
|
||||
* Cambia el Sprite de las pelotas
|
||||
* NO PUEDE cambiar a la figura PNG_SHAPE
|
||||
* Eventualmente puede cambiar de manera automatica a LOGO LITE, sin restricciones
|
||||
* El usuario puede cambiar el SimulationMode, el Theme o el Scene. Esto no hace que se salga del modo DEMO
|
||||
* El usuario puede cambiar de AppMode pulsando:
|
||||
* D: SANDBOX
|
||||
* L: DEMO LITE
|
||||
* K: LOGO
|
||||
* DEMO LITE
|
||||
* En el modo DEMO el programa va cambiando el SimulationMode de manera automatica (como está ahora es correcto)
|
||||
* Se inicializa con un Theme al azar, Scene al azar, SimulationMode al azar. Restringido FIGURE->PNG_SHAPE
|
||||
* Este modo es exactamente igual a DEMO pero NO PUEDE:
|
||||
* Cambiar de Scene
|
||||
* Cambiar de Theme
|
||||
* Cambiar el Sprite de las pelotas
|
||||
* Eventualmente puede cambiar de manera automatica a LOGO LITE, sin restricciones
|
||||
* NO PUEDE cambiar a la figura PNG_SHAPE
|
||||
* El usuario puede cambiar el SimulationMode, el Theme o el Scene. Esto no hace que se salga del modo DEMO LITE
|
||||
* El usuario puede cambiar de AppMode pulsando:
|
||||
* D: DEMO
|
||||
* L: SANDBOX
|
||||
* K: LOGO
|
||||
* LOGO
|
||||
* Se inicializa con la Scene de 5.000 pelotas, con el tamaño de Sprite->Small, con SimulationMode en FIGURE->PNG_SHAPE, con un tema al azar de los permitidos
|
||||
* No cambia de Scene
|
||||
* No cambia el tamaño de Sprite
|
||||
* No cambia la escala de FIGURE
|
||||
* Los temas permitidos son MONOCROMO, LAVANDA, CARMESI, ESMERALDA o cualquiera de los temas dinamicos
|
||||
* En este modo SOLO aparece la figura PNG_SHAPE
|
||||
* Solo cambiara a los temas permitidos
|
||||
* Cambia el SimulationMode de PHYSICS a FIGURE (como hace ahora) pero no a BOIDS. BOIDS prohibido
|
||||
* El usuario puede cambiar el SimulationMode, el Theme o el Scene. Esto no hace que se salga del modo LOGO. Incluso puede poner un Theme no permitido o otro Scene.
|
||||
* El automatismo no cambia nunca de Theme así que se mantiene el del usuario.
|
||||
* El automatismo no cambia nunca de Scene asi que se mantiene el del usuario.
|
||||
* El usuario puede cambiar de AppMode pulsando:
|
||||
* D: DEMO
|
||||
* L: DEMO LITE
|
||||
* K: SANDBOX
|
||||
* B: SANDBOX->BOIDS
|
||||
* LOGO LITE
|
||||
* Este modo es exactamente igual al modo LOGO pero con unas pequeñas diferencias:
|
||||
* Solo se accede a el de manera automatica, el usuario no puede invocarlo. No hay tecla
|
||||
* Como se accede de manera automatica solo se puede llegar a él desde DEMO o DEMO LITE. Hay que guardar el estado en el que se encontraba AppMode, EngindeMode, Scene, Theme, Sprite, Scale... etc
|
||||
* Este modo tiene una muy alta probabilidad de terminar, volviendo al estado anterior desde donde se invocó.
|
||||
* El usuario puede cambiar de AppMode pulsando:
|
||||
* D: Si el modo anterior era DEMO -> SANDBOX, else -> DEMO)
|
||||
* L: Si el modo anterior era DEMO LITE -> SANDBOX, else -> DEMO LITE)
|
||||
* K: LOGO
|
||||
* B: SANDBOX->BOIDS
|
||||
|
||||
|
||||
# Debug Hud
|
||||
* En el debug hud hay que añadir que se vea SIEMPRE el AppMode (actualmente aparece centrado, hay que ponerlo a la izquierda) y no solo cietos AppModes
|
||||
* Tiene que aparecer tambien el SimulationMode
|
||||
* El modo de Vsync
|
||||
* El modo de escalado entero, stretched, ventana
|
||||
* la resolucion fisica
|
||||
* la resolucion logica
|
||||
* el refresco del panel
|
||||
* El resto de cosas que salen
|
||||
|
||||
# Ventana de ayuda
|
||||
* La ventana de ayuda actualmente es cuadrada
|
||||
* Esa es la anchura minima que ha de tener
|
||||
* Hay que ver cual es la linea mas larga, multiplicarla por el numero de columnas, añadirle los paddings y que ese sea el nuevo ancho
|
||||
* Actualmente se renderiza a cada frame. El rendimiento cae de los 1200 frames por segundo a 200 frames por segundo. Habria que renderizarla a una textura o algo. El problema es que el cambio de Theme con LERP afecta a los colores de la ventana. Hay que investigar qué se puede hacer.
|
||||
|
||||
# Bugs actuales
|
||||
* En el modo LOGO, si se pulsa un cursor, se activa la gravedad y deja de funcionar los automatismos. Incluso he llegado a ver como sale solo del modo LOGO sin pulsar nada
|
||||
* En el modo BOIDS, pulsar la G activa la gravedad. La G deberia pasar al modo PHYSICS con la gravedad en OFF y que las pelotas mantuvieran el momento/inercia
|
||||
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>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.15</string>
|
||||
<string>12.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
BIN
release/SDL3.dll
Normal file
BIN
release/SDL3.dll
Normal file
Binary file not shown.
BIN
release/SDL3_ttf.dll
Normal file
BIN
release/SDL3_ttf.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 <cmath> // for fabs
|
||||
|
||||
#include "defines.h" // for Color, SCREEN_HEIGHT, GRAVITY_FORCE
|
||||
#include "defines.hpp" // for Color, SCREEN_HEIGHT, GRAVITY_FORCE
|
||||
class Texture;
|
||||
|
||||
// Función auxiliar para generar pérdida aleatoria en rebotes
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <memory> // for shared_ptr, unique_ptr
|
||||
|
||||
#include "defines.h" // for Color
|
||||
#include "external/sprite.h" // for Sprite
|
||||
#include "defines.hpp" // for Color
|
||||
#include "external/sprite.hpp" // for Sprite
|
||||
class Texture;
|
||||
|
||||
class Ball {
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "boid_manager.h"
|
||||
#include "boid_manager.hpp"
|
||||
|
||||
#include <algorithm> // for std::min, std::max
|
||||
#include <cmath> // for sqrt, atan2
|
||||
|
||||
#include "../ball.h" // for Ball
|
||||
#include "../engine.h" // for Engine (si se necesita)
|
||||
#include "../scene/scene_manager.h" // for SceneManager
|
||||
#include "../state/state_manager.h" // for StateManager
|
||||
#include "../ui/ui_manager.h" // for UIManager
|
||||
#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)
|
||||
@@ -17,7 +17,18 @@ BoidManager::BoidManager()
|
||||
, 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()
|
||||
, 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() {
|
||||
@@ -57,9 +68,9 @@ void BoidManager::activateBoids() {
|
||||
float vx, vy;
|
||||
ball->getVelocity(vx, vy);
|
||||
if (vx == 0.0f && vy == 0.0f) {
|
||||
// Velocidad aleatoria entre -1 y 1
|
||||
vx = (rand() % 200 - 100) / 100.0f;
|
||||
vy = (rand() % 200 - 100) / 100.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);
|
||||
}
|
||||
}
|
||||
@@ -118,14 +129,14 @@ void BoidManager::update(float delta_time) {
|
||||
limitSpeed(ball.get());
|
||||
}
|
||||
|
||||
// Actualizar posiciones con velocidades resultantes
|
||||
// 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;
|
||||
pos.y += vy;
|
||||
pos.x += vx * delta_time; // time-based
|
||||
pos.y += vy * delta_time;
|
||||
|
||||
ball->setPosition(pos.x, pos.y);
|
||||
}
|
||||
@@ -146,7 +157,7 @@ void BoidManager::applySeparation(Ball* boid, float delta_time) {
|
||||
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, BOID_SEPARATION_RADIUS);
|
||||
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, separation_radius_);
|
||||
|
||||
for (Ball* other : neighbors) {
|
||||
if (other == boid) continue; // Ignorar a sí mismo
|
||||
@@ -159,10 +170,10 @@ void BoidManager::applySeparation(Ball* boid, float delta_time) {
|
||||
float dy = center_y - other_y;
|
||||
float distance = std::sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance > 0.0f && distance < BOID_SEPARATION_RADIUS) {
|
||||
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 = (BOID_SEPARATION_RADIUS - distance) / BOID_SEPARATION_RADIUS;
|
||||
float separation_strength = (separation_radius_ - distance) / separation_radius_;
|
||||
steer_x += (dx / distance) * separation_strength;
|
||||
steer_y += (dy / distance) * separation_strength;
|
||||
count++;
|
||||
@@ -177,8 +188,8 @@ void BoidManager::applySeparation(Ball* boid, float delta_time) {
|
||||
// Aplicar fuerza de separación
|
||||
float vx, vy;
|
||||
boid->getVelocity(vx, vy);
|
||||
vx += steer_x * BOID_SEPARATION_WEIGHT * delta_time;
|
||||
vy += steer_y * BOID_SEPARATION_WEIGHT * delta_time;
|
||||
vx += steer_x * separation_weight_ * delta_time;
|
||||
vy += steer_y * separation_weight_ * delta_time;
|
||||
boid->setVelocity(vx, vy);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +205,7 @@ void BoidManager::applyAlignment(Ball* boid, float delta_time) {
|
||||
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, BOID_ALIGNMENT_RADIUS);
|
||||
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, alignment_radius_);
|
||||
|
||||
for (Ball* other : neighbors) {
|
||||
if (other == boid) continue;
|
||||
@@ -207,7 +218,7 @@ void BoidManager::applyAlignment(Ball* boid, float delta_time) {
|
||||
float dy = center_y - other_y;
|
||||
float distance = std::sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < BOID_ALIGNMENT_RADIUS) {
|
||||
if (distance < alignment_radius_) {
|
||||
float other_vx, other_vy;
|
||||
other->getVelocity(other_vx, other_vy);
|
||||
avg_vx += other_vx;
|
||||
@@ -224,14 +235,14 @@ void BoidManager::applyAlignment(Ball* boid, float delta_time) {
|
||||
// Steering hacia la velocidad promedio
|
||||
float vx, vy;
|
||||
boid->getVelocity(vx, vy);
|
||||
float steer_x = (avg_vx - vx) * BOID_ALIGNMENT_WEIGHT * delta_time;
|
||||
float steer_y = (avg_vy - vy) * BOID_ALIGNMENT_WEIGHT * delta_time;
|
||||
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 > BOID_MAX_FORCE) {
|
||||
steer_x = (steer_x / steer_mag) * BOID_MAX_FORCE;
|
||||
steer_y = (steer_y / steer_mag) * BOID_MAX_FORCE;
|
||||
if (steer_mag > max_force_) {
|
||||
steer_x = (steer_x / steer_mag) * max_force_;
|
||||
steer_y = (steer_y / steer_mag) * max_force_;
|
||||
}
|
||||
|
||||
vx += steer_x;
|
||||
@@ -251,7 +262,7 @@ void BoidManager::applyCohesion(Ball* boid, float delta_time) {
|
||||
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, BOID_COHESION_RADIUS);
|
||||
auto neighbors = spatial_grid_.queryRadius(center_x, center_y, cohesion_radius_);
|
||||
|
||||
for (Ball* other : neighbors) {
|
||||
if (other == boid) continue;
|
||||
@@ -264,7 +275,7 @@ void BoidManager::applyCohesion(Ball* boid, float delta_time) {
|
||||
float dy = center_y - other_y;
|
||||
float distance = std::sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < BOID_COHESION_RADIUS) {
|
||||
if (distance < cohesion_radius_) {
|
||||
center_of_mass_x += other_x;
|
||||
center_of_mass_y += other_y;
|
||||
count++;
|
||||
@@ -284,14 +295,14 @@ void BoidManager::applyCohesion(Ball* boid, float delta_time) {
|
||||
// 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) * BOID_COHESION_WEIGHT * delta_time;
|
||||
float steer_y = (dy_to_center / distance_to_center) * BOID_COHESION_WEIGHT * delta_time;
|
||||
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 > BOID_MAX_FORCE) {
|
||||
steer_x = (steer_x / steer_mag) * BOID_MAX_FORCE;
|
||||
steer_y = (steer_y / steer_mag) * BOID_MAX_FORCE;
|
||||
if (steer_mag > max_force_) {
|
||||
steer_x = (steer_x / steer_mag) * max_force_;
|
||||
steer_y = (steer_y / steer_mag) * max_force_;
|
||||
}
|
||||
|
||||
float vx, vy;
|
||||
@@ -304,32 +315,69 @@ void BoidManager::applyCohesion(Ball* boid, float delta_time) {
|
||||
}
|
||||
|
||||
void BoidManager::applyBoundaries(Ball* boid) {
|
||||
// Mantener boids dentro de los límites de la pantalla
|
||||
// Comportamiento "wrapping" (teletransporte al otro lado)
|
||||
// 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;
|
||||
|
||||
bool wrapped = false;
|
||||
float steer_x = 0.0f;
|
||||
float steer_y = 0.0f;
|
||||
|
||||
if (center_x < 0) {
|
||||
pos.x = screen_width_ - pos.w / 2.0f;
|
||||
wrapped = true;
|
||||
} else if (center_x > screen_width_) {
|
||||
pos.x = -pos.w / 2.0f;
|
||||
wrapped = true;
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
if (center_y < 0) {
|
||||
pos.y = screen_height_ - pos.h / 2.0f;
|
||||
wrapped = true;
|
||||
} else if (center_y > screen_height_) {
|
||||
pos.y = -pos.h / 2.0f;
|
||||
wrapped = true;
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
if (wrapped) {
|
||||
boid->setPosition(pos.x, pos.y);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,16 +389,16 @@ void BoidManager::limitSpeed(Ball* boid) {
|
||||
float speed = std::sqrt(vx * vx + vy * vy);
|
||||
|
||||
// Limitar velocidad máxima
|
||||
if (speed > BOID_MAX_SPEED) {
|
||||
vx = (vx / speed) * BOID_MAX_SPEED;
|
||||
vy = (vy / speed) * BOID_MAX_SPEED;
|
||||
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 < BOID_MIN_SPEED) {
|
||||
vx = (vx / speed) * BOID_MIN_SPEED;
|
||||
vy = (vy / speed) * BOID_MIN_SPEED;
|
||||
if (speed > 0.0f && speed < min_speed_) {
|
||||
vx = (vx / speed) * min_speed_;
|
||||
vy = (vy / speed) * min_speed_;
|
||||
boid->setVelocity(vx, vy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <cstddef> // for size_t
|
||||
|
||||
#include "../defines.h" // for SimulationMode, AppMode
|
||||
#include "../spatial_grid.h" // for SpatialGrid
|
||||
#include "defines.hpp" // for SimulationMode, AppMode
|
||||
#include "spatial_grid.hpp" // for SpatialGrid
|
||||
|
||||
// Forward declarations
|
||||
class Engine;
|
||||
@@ -103,10 +103,24 @@ class BoidManager {
|
||||
// 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); // Mantener boids dentro de pantalla
|
||||
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)";
|
||||
|
||||
// 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_HEIGHT = 240; // 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_SCREEN_WIDTH = 1280; // Ancho lógico por defecto (si no hay -w)
|
||||
constexpr int DEFAULT_SCREEN_HEIGHT = 720; // Alto lógico por defecto (si no hay -h)
|
||||
constexpr int DEFAULT_WINDOW_ZOOM = 1; // Zoom inicial de ventana (1x = sin zoom)
|
||||
|
||||
// Configuración de zoom dinámico de ventana
|
||||
constexpr int WINDOW_ZOOM_MIN = 1; // Zoom mínimo (320x240)
|
||||
@@ -22,17 +22,16 @@ constexpr int WINDOW_DECORATION_HEIGHT = 30; // Altura estimada de decoraciones
|
||||
constexpr float GRAVITY_FORCE = 0.2f; // Fuerza de gravedad (píxeles/frame²)
|
||||
|
||||
// Configuración de interfaz
|
||||
constexpr Uint64 TEXT_DURATION = 2000; // Duración del texto informativo (ms) - OBSOLETO, usar NOTIFICATION_DURATION
|
||||
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 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)
|
||||
|
||||
// Configuración de pérdida aleatoria en rebotes
|
||||
constexpr float BASE_BOUNCE_COEFFICIENT = 0.75f; // Coeficiente base IGUAL para todas las pelotas
|
||||
@@ -60,12 +59,12 @@ struct Color {
|
||||
|
||||
// Estructura de tema de colores estático
|
||||
struct ThemeColors {
|
||||
const char* name_en; // Nombre en inglés (para debug)
|
||||
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
|
||||
float bg_top_r, bg_top_g, bg_top_b;
|
||||
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
||||
std::vector<Color> ball_colors;
|
||||
const char* name_en; // Nombre en inglés (para debug)
|
||||
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
|
||||
float bg_top_r, bg_top_g, bg_top_b;
|
||||
float bg_bottom_r, bg_bottom_g, bg_bottom_b;
|
||||
std::vector<Color> ball_colors;
|
||||
};
|
||||
|
||||
// Estructura para keyframe de tema dinámico
|
||||
@@ -99,21 +98,21 @@ enum class GravityDirection {
|
||||
// Enum para temas de colores (seleccionables con teclado numérico y Shift+Numpad)
|
||||
// Todos los temas usan ahora sistema dinámico de keyframes
|
||||
enum class ColorTheme {
|
||||
SUNSET = 0, // Naranjas, rojos, amarillos, rosas (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)
|
||||
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)
|
||||
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)
|
||||
CRIMSON = 7, // Fondo negro-rojo, pelotas rojas uniformes (estático: 1 keyframe)
|
||||
EMERALD = 8, // Fondo negro-verde, pelotas verdes uniformes (estático: 1 keyframe)
|
||||
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)
|
||||
SUNSET = 0, // Naranjas, rojos, amarillos, rosas (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)
|
||||
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)
|
||||
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)
|
||||
CRIMSON = 7, // Fondo negro-rojo, pelotas rojas uniformes (estático: 1 keyframe)
|
||||
EMERALD = 8, // Fondo negro-verde, pelotas verdes uniformes (estático: 1 keyframe)
|
||||
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
|
||||
@@ -282,27 +281,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)
|
||||
|
||||
// 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_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_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_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 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 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)
|
||||
// FASE 1.1 REVISADA: Parámetros ajustados tras detectar cohesión mal normalizada
|
||||
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 = 1.5f; // Peso de separación
|
||||
constexpr float BOID_ALIGNMENT_WEIGHT = 1.0f; // Peso de alineación
|
||||
constexpr float BOID_COHESION_WEIGHT = 0.001f; // Peso de cohesión (MICRO - 1000x menor por falta de normalización)
|
||||
constexpr float BOID_MAX_SPEED = 2.5f; // Velocidad máxima (píxeles/frame - REDUCIDA)
|
||||
constexpr float BOID_MAX_FORCE = 0.05f; // Fuerza máxima de steering (REDUCIDA para evitar aceleración excesiva)
|
||||
constexpr float BOID_MIN_SPEED = 0.3f; // Velocidad mínima (evita boids estáticos)
|
||||
// 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
|
||||
// Debe ser ≥ BOID_COHESION_RADIUS para funcionar correctamente
|
||||
|
||||
constexpr float PI = 3.14159265358979323846f; // Constante PI
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "engine.h"
|
||||
#include "engine.hpp"
|
||||
|
||||
#include <SDL3/SDL_error.h> // for SDL_GetError
|
||||
#include <SDL3/SDL_events.h> // for SDL_Event, SDL_PollEvent
|
||||
@@ -17,27 +17,29 @@
|
||||
#include <iostream> // for cout
|
||||
#include <string> // for string
|
||||
|
||||
#include "resource_manager.hpp" // for ResourceManager
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // for GetModuleFileName
|
||||
#endif
|
||||
|
||||
#include "ball.h" // for Ball
|
||||
#include "external/mouse.h" // for Mouse namespace
|
||||
#include "external/texture.h" // for Texture
|
||||
#include "shapes/atom_shape.h" // for AtomShape
|
||||
#include "shapes/cube_shape.h" // for CubeShape
|
||||
#include "shapes/cylinder_shape.h" // for CylinderShape
|
||||
#include "shapes/helix_shape.h" // for HelixShape
|
||||
#include "shapes/icosahedron_shape.h" // for IcosahedronShape
|
||||
#include "shapes/lissajous_shape.h" // for LissajousShape
|
||||
#include "shapes/png_shape.h" // for PNGShape
|
||||
#include "shapes/sphere_shape.h" // for SphereShape
|
||||
#include "shapes/torus_shape.h" // for TorusShape
|
||||
#include "ball.hpp" // for Ball
|
||||
#include "external/mouse.hpp" // for Mouse namespace
|
||||
#include "external/texture.hpp" // for Texture
|
||||
#include "shapes/atom_shape.hpp" // for AtomShape
|
||||
#include "shapes/cube_shape.hpp" // for CubeShape
|
||||
#include "shapes/cylinder_shape.hpp" // for CylinderShape
|
||||
#include "shapes/helix_shape.hpp" // for HelixShape
|
||||
#include "shapes/icosahedron_shape.hpp" // for IcosahedronShape
|
||||
#include "shapes/lissajous_shape.hpp" // for LissajousShape
|
||||
#include "shapes/png_shape.hpp" // for PNGShape
|
||||
#include "shapes/sphere_shape.hpp" // for SphereShape
|
||||
#include "shapes/torus_shape.hpp" // for TorusShape
|
||||
|
||||
// getExecutableDirectory() ya está definido en defines.h como inline
|
||||
|
||||
// Implementación de métodos públicos
|
||||
bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
|
||||
bool Engine::initialize(int width, int height, int zoom, bool fullscreen, AppMode initial_mode) {
|
||||
bool success = true;
|
||||
|
||||
// Obtener resolución de pantalla para validación
|
||||
@@ -164,9 +166,9 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: cargar texturas desde pack usando la lista del ResourcePack
|
||||
if (Texture::isPackLoaded()) {
|
||||
auto pack_resources = Texture::getPackResourceList();
|
||||
// Fallback: cargar texturas desde pack usando la lista del ResourceManager
|
||||
if (ResourceManager::isPackLoaded()) {
|
||||
auto pack_resources = ResourceManager::getResourceList();
|
||||
|
||||
// Filtrar solo los recursos en balls/ con extensión .png
|
||||
for (const auto& resource : pack_resources) {
|
||||
@@ -235,7 +237,9 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
|
||||
// Inicializar UIManager (HUD, FPS, notificaciones)
|
||||
// NOTA: Debe llamarse DESPUÉS de calcular physical_window_* y ThemeManager
|
||||
ui_manager_ = std::make_unique<UIManager>();
|
||||
ui_manager_->initialize(renderer_, theme_manager_.get(), physical_window_width_, physical_window_height_);
|
||||
ui_manager_->initialize(renderer_, theme_manager_.get(),
|
||||
physical_window_width_, physical_window_height_,
|
||||
current_screen_width_, current_screen_height_);
|
||||
|
||||
// Inicializar ShapeManager (gestión de figuras 3D)
|
||||
shape_manager_ = std::make_unique<ShapeManager>();
|
||||
@@ -246,6 +250,22 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
|
||||
state_manager_ = std::make_unique<StateManager>();
|
||||
state_manager_->initialize(this); // Callback al Engine
|
||||
|
||||
// Establecer modo inicial si no es SANDBOX (default)
|
||||
// Usar métodos de alto nivel que ejecutan las acciones de configuración
|
||||
if (initial_mode == AppMode::DEMO) {
|
||||
state_manager_->toggleDemoMode(current_screen_width_, current_screen_height_);
|
||||
// Como estamos en SANDBOX (default), toggleDemoMode() cambiará a DEMO + randomizará
|
||||
}
|
||||
else if (initial_mode == AppMode::DEMO_LITE) {
|
||||
state_manager_->toggleDemoLiteMode(current_screen_width_, current_screen_height_);
|
||||
// Como estamos en SANDBOX (default), toggleDemoLiteMode() cambiará a DEMO_LITE + randomizará
|
||||
}
|
||||
else if (initial_mode == AppMode::LOGO) {
|
||||
size_t initial_ball_count = scene_manager_->getBallCount();
|
||||
state_manager_->enterLogoMode(false, current_screen_width_, current_screen_height_, initial_ball_count);
|
||||
// enterLogoMode() hace: setState(LOGO) + executeEnterLogoMode() (tema, PNG_SHAPE, etc.)
|
||||
}
|
||||
|
||||
// Actualizar ShapeManager con StateManager (dependencia circular - StateManager debe existir primero)
|
||||
shape_manager_->initialize(this, scene_manager_.get(), ui_manager_.get(), state_manager_.get(),
|
||||
current_screen_width_, current_screen_height_);
|
||||
@@ -254,6 +274,14 @@ bool Engine::initialize(int width, int height, int zoom, bool fullscreen) {
|
||||
boid_manager_ = std::make_unique<BoidManager>();
|
||||
boid_manager_->initialize(this, scene_manager_.get(), ui_manager_.get(), state_manager_.get(),
|
||||
current_screen_width_, current_screen_height_);
|
||||
|
||||
// Inicializar AppLogo (logo periódico en pantalla)
|
||||
app_logo_ = std::make_unique<AppLogo>();
|
||||
if (!app_logo_->initialize(renderer_, current_screen_width_, current_screen_height_)) {
|
||||
std::cerr << "Advertencia: No se pudo inicializar AppLogo (logo periódico)" << std::endl;
|
||||
// No es crítico, continuar sin logo
|
||||
app_logo_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -334,6 +362,11 @@ void Engine::update() {
|
||||
|
||||
// Actualizar transiciones de temas (delegado a ThemeManager)
|
||||
theme_manager_->update(delta_time_);
|
||||
|
||||
// Actualizar AppLogo (logo periódico)
|
||||
if (app_logo_) {
|
||||
app_logo_->update(delta_time_, state_manager_->getCurrentMode());
|
||||
}
|
||||
}
|
||||
|
||||
// === IMPLEMENTACIÓN DE MÉTODOS PÚBLICOS PARA INPUT HANDLER ===
|
||||
@@ -343,7 +376,7 @@ void Engine::handleGravityToggle() {
|
||||
// Si estamos en modo boids, salir a modo física CON GRAVEDAD OFF
|
||||
// Según RULES.md: "BOIDS a PHYSICS: Pulsando la tecla G: Gravedad OFF"
|
||||
if (current_mode_ == SimulationMode::BOIDS) {
|
||||
toggleBoidsMode(); // Cambiar a PHYSICS (preserva inercia, gravedad ya está OFF desde activateBoids)
|
||||
toggleBoidsMode(false); // Cambiar a PHYSICS sin activar gravedad (preserva inercia)
|
||||
// NO llamar a forceBallsGravityOff() porque aplica impulsos que destruyen la inercia de BOIDS
|
||||
// La gravedad ya está desactivada por BoidManager::activateBoids() y se mantiene al salir
|
||||
showNotificationForAction("Modo Física - Gravedad Off");
|
||||
@@ -364,18 +397,19 @@ void Engine::handleGravityToggle() {
|
||||
}
|
||||
|
||||
void Engine::handleGravityDirectionChange(GravityDirection direction, const char* notification_text) {
|
||||
// Si estamos en modo boids, salir a modo física primero
|
||||
// Si estamos en modo boids, salir a modo física primero PRESERVANDO VELOCIDAD
|
||||
if (current_mode_ == SimulationMode::BOIDS) {
|
||||
toggleBoidsMode(); // Esto cambia a PHYSICS y activa gravedad
|
||||
// Continuar para aplicar la dirección de gravedad
|
||||
current_mode_ = SimulationMode::PHYSICS;
|
||||
boid_manager_->deactivateBoids(false); // NO activar gravedad aún (preservar momentum)
|
||||
scene_manager_->forceBallsGravityOn(); // Activar gravedad SIN impulsos (preserva velocidad)
|
||||
}
|
||||
|
||||
// Si estamos en modo figura, salir a modo física CON gravedad
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
else if (current_mode_ == SimulationMode::SHAPE) {
|
||||
toggleShapeModeInternal(); // Desactivar figura (activa gravedad automáticamente)
|
||||
} else {
|
||||
scene_manager_->enableBallsGravityIfDisabled(); // Reactivar gravedad si estaba OFF
|
||||
}
|
||||
|
||||
scene_manager_->changeGravityDirection(direction);
|
||||
showNotificationForAction(notification_text);
|
||||
}
|
||||
@@ -435,11 +469,11 @@ void Engine::toggleDepthZoom() {
|
||||
}
|
||||
|
||||
// Boids (comportamiento de enjambre)
|
||||
void Engine::toggleBoidsMode() {
|
||||
void Engine::toggleBoidsMode(bool force_gravity_on) {
|
||||
if (current_mode_ == SimulationMode::BOIDS) {
|
||||
// Salir del modo boids
|
||||
// Salir del modo boids (velocidades ya son time-based, no requiere conversión)
|
||||
current_mode_ = SimulationMode::PHYSICS;
|
||||
boid_manager_->deactivateBoids();
|
||||
boid_manager_->deactivateBoids(force_gravity_on); // Pasar parámetro para control preciso
|
||||
} else {
|
||||
// Entrar al modo boids (desde PHYSICS o SHAPE)
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
@@ -522,6 +556,11 @@ void Engine::changeScenario(int scenario_id, const char* notification_text) {
|
||||
}
|
||||
}
|
||||
|
||||
// Si estamos en modo BOIDS, desactivar gravedad (modo BOIDS = gravedad OFF siempre)
|
||||
if (current_mode_ == SimulationMode::BOIDS) {
|
||||
scene_manager_->forceBallsGravityOff();
|
||||
}
|
||||
|
||||
showNotificationForAction(notification_text);
|
||||
}
|
||||
|
||||
@@ -710,6 +749,11 @@ void Engine::render() {
|
||||
active_shape_.get(), shape_convergence_,
|
||||
physical_window_width_, physical_window_height_, current_screen_width_);
|
||||
|
||||
// Renderizar AppLogo (logo periódico) - después de UI, antes de present
|
||||
if (app_logo_) {
|
||||
app_logo_->render();
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer_);
|
||||
}
|
||||
|
||||
@@ -790,6 +834,22 @@ void Engine::toggleRealFullscreen() {
|
||||
|
||||
// Actualizar tamaño de pantalla para boids (wrapping boundaries)
|
||||
boid_manager_->updateScreenSize(current_screen_width_, current_screen_height_);
|
||||
|
||||
// Actualizar AppLogo con nueva resolución
|
||||
if (app_logo_) {
|
||||
app_logo_->updateScreenSize(current_screen_width_, current_screen_height_);
|
||||
}
|
||||
|
||||
// Si estamos en modo SHAPE, regenerar la figura con nuevas dimensiones
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
generateShape(); // Regenerar figura con nuevas dimensiones de pantalla
|
||||
|
||||
// Activar atracción física en las bolas nuevas (crítico tras changeScenario)
|
||||
auto& balls = scene_manager_->getBallsMutable();
|
||||
for (auto& ball : balls) {
|
||||
ball->enableShapeAttraction(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_free(displays);
|
||||
}
|
||||
@@ -812,6 +872,22 @@ void Engine::toggleRealFullscreen() {
|
||||
// Reinicar la escena con resolución original
|
||||
scene_manager_->updateScreenSize(current_screen_width_, current_screen_height_);
|
||||
scene_manager_->changeScenario(scene_manager_->getCurrentScenario(), current_mode_);
|
||||
|
||||
// Actualizar AppLogo con resolución restaurada
|
||||
if (app_logo_) {
|
||||
app_logo_->updateScreenSize(current_screen_width_, current_screen_height_);
|
||||
}
|
||||
|
||||
// Si estamos en modo SHAPE, regenerar la figura con nuevas dimensiones
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
generateShape(); // Regenerar figura con nuevas dimensiones de pantalla
|
||||
|
||||
// Activar atracción física en las bolas nuevas (crítico tras changeScenario)
|
||||
auto& balls = scene_manager_->getBallsMutable();
|
||||
for (auto& ball : balls) {
|
||||
ball->enableShapeAttraction(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1337,6 +1413,18 @@ void Engine::executeDemoAction(bool is_lite) {
|
||||
int valid_scenarios[] = {1, 2, 3, 4, 5};
|
||||
int new_scenario = valid_scenarios[rand() % 5];
|
||||
scene_manager_->changeScenario(new_scenario, current_mode_);
|
||||
|
||||
// Si estamos en modo SHAPE, regenerar la figura con nuevo número de pelotas
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
generateShape();
|
||||
|
||||
// Activar atracción física en las bolas nuevas (crítico tras changeScenario)
|
||||
auto& balls = scene_manager_->getBallsMutable();
|
||||
for (auto& ball : balls) {
|
||||
ball->enableShapeAttraction(true);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1418,21 +1506,7 @@ void Engine::executeRandomizeOnDemoStart(bool is_lite) {
|
||||
} else {
|
||||
// DEMO COMPLETO: Randomizar TODO
|
||||
|
||||
// 1. Escenario (excluir índices 0, 6, 7)
|
||||
int valid_scenarios[] = {1, 2, 3, 4, 5};
|
||||
int new_scenario = valid_scenarios[rand() % 5];
|
||||
scene_manager_->changeScenario(new_scenario, current_mode_);
|
||||
|
||||
// 2. Tema (elegir entre TODOS los 15 temas)
|
||||
int random_theme_index = rand() % 15;
|
||||
theme_manager_->switchToTheme(random_theme_index);
|
||||
|
||||
// 3. Sprite
|
||||
if (rand() % 2 == 0) {
|
||||
switchTextureInternal(false); // Suprimir notificación al activar modo DEMO
|
||||
}
|
||||
|
||||
// 4. Física o Figura
|
||||
// 1. Física o Figura (decidir PRIMERO antes de cambiar escenario)
|
||||
if (rand() % 2 == 0) {
|
||||
// Modo física
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
@@ -1441,20 +1515,83 @@ void Engine::executeRandomizeOnDemoStart(bool is_lite) {
|
||||
} else {
|
||||
// Modo figura: elegir figura aleatoria (excluir PNG_SHAPE - es logo especial)
|
||||
ShapeType shapes[] = {ShapeType::SPHERE, ShapeType::LISSAJOUS, ShapeType::HELIX, ShapeType::TORUS, ShapeType::CUBE, ShapeType::CYLINDER, ShapeType::ICOSAHEDRON, ShapeType::ATOM};
|
||||
activateShapeInternal(shapes[rand() % 8]);
|
||||
ShapeType selected_shape = shapes[rand() % 8];
|
||||
|
||||
// 5. Profundidad (solo si estamos en figura)
|
||||
// Configurar figura SIN generar puntos (changeScenario lo hará después)
|
||||
last_shape_type_ = selected_shape;
|
||||
current_shape_type_ = selected_shape;
|
||||
current_mode_ = SimulationMode::SHAPE;
|
||||
|
||||
// Crear instancia de la figura sin generar puntos todavía
|
||||
switch (selected_shape) {
|
||||
case ShapeType::SPHERE:
|
||||
active_shape_ = std::make_unique<SphereShape>();
|
||||
break;
|
||||
case ShapeType::CUBE:
|
||||
active_shape_ = std::make_unique<CubeShape>();
|
||||
break;
|
||||
case ShapeType::HELIX:
|
||||
active_shape_ = std::make_unique<HelixShape>();
|
||||
break;
|
||||
case ShapeType::TORUS:
|
||||
active_shape_ = std::make_unique<TorusShape>();
|
||||
break;
|
||||
case ShapeType::LISSAJOUS:
|
||||
active_shape_ = std::make_unique<LissajousShape>();
|
||||
break;
|
||||
case ShapeType::CYLINDER:
|
||||
active_shape_ = std::make_unique<CylinderShape>();
|
||||
break;
|
||||
case ShapeType::ICOSAHEDRON:
|
||||
active_shape_ = std::make_unique<IcosahedronShape>();
|
||||
break;
|
||||
case ShapeType::ATOM:
|
||||
active_shape_ = std::make_unique<AtomShape>();
|
||||
break;
|
||||
default:
|
||||
active_shape_ = std::make_unique<SphereShape>();
|
||||
break;
|
||||
}
|
||||
|
||||
// Profundidad (solo si estamos en figura)
|
||||
if (rand() % 2 == 0) {
|
||||
depth_zoom_enabled_ = !depth_zoom_enabled_;
|
||||
}
|
||||
|
||||
// 6. Escala de figura (aleatoria entre 0.5x y 2.0x)
|
||||
// Escala de figura (aleatoria entre 0.5x y 2.0x)
|
||||
shape_scale_factor_ = 0.5f + (rand() % 1500) / 1000.0f;
|
||||
clampShapeScale();
|
||||
generateShape();
|
||||
|
||||
// NOTA: NO llamar a generateShape() ni activar atracción aquí
|
||||
// changeScenario() creará las pelotas y luego llamará a generateShape()
|
||||
}
|
||||
|
||||
// 7. Gravedad: dirección + ON/OFF
|
||||
// 2. Escenario (excluir índices 0, 6, 7) - AHORA con current_mode_ ya establecido correctamente
|
||||
int valid_scenarios[] = {1, 2, 3, 4, 5};
|
||||
int new_scenario = valid_scenarios[rand() % 5];
|
||||
scene_manager_->changeScenario(new_scenario, current_mode_);
|
||||
|
||||
// Si estamos en modo SHAPE, generar la figura y activar atracción
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
generateShape();
|
||||
|
||||
// Activar atracción física en las bolas nuevas
|
||||
auto& balls = scene_manager_->getBallsMutable();
|
||||
for (auto& ball : balls) {
|
||||
ball->enableShapeAttraction(true);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Tema (elegir entre TODOS los 15 temas)
|
||||
int random_theme_index = rand() % 15;
|
||||
theme_manager_->switchToTheme(random_theme_index);
|
||||
|
||||
// 4. Sprite
|
||||
if (rand() % 2 == 0) {
|
||||
switchTextureInternal(false); // Suprimir notificación al activar modo DEMO
|
||||
}
|
||||
|
||||
// 5. Gravedad: dirección + ON/OFF
|
||||
GravityDirection new_direction = static_cast<GravityDirection>(rand() % 4);
|
||||
scene_manager_->changeGravityDirection(new_direction);
|
||||
if (rand() % 3 == 0) { // 33% probabilidad de desactivar gravedad
|
||||
@@ -1551,6 +1688,15 @@ void Engine::executeExitLogoMode() {
|
||||
clampShapeScale();
|
||||
generateShape();
|
||||
|
||||
// Activar atracción física si estamos en modo SHAPE
|
||||
// (crítico para que las bolas se muevan hacia la figura restaurada)
|
||||
if (current_mode_ == SimulationMode::SHAPE) {
|
||||
auto& balls = scene_manager_->getBallsMutable();
|
||||
for (auto& ball : balls) {
|
||||
ball->enableShapeAttraction(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Desactivar modo LOGO en PNG_SHAPE (volver a flip intervals normales)
|
||||
if (active_shape_) {
|
||||
PNGShape* png_shape = dynamic_cast<PNGShape*>(active_shape_.get());
|
||||
|
||||
@@ -10,22 +10,23 @@
|
||||
#include <string> // for string
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ball.h" // for Ball
|
||||
#include "boids_mgr/boid_manager.h" // for BoidManager
|
||||
#include "defines.h" // for GravityDirection, ColorTheme, ShapeType
|
||||
#include "external/texture.h" // for Texture
|
||||
#include "input/input_handler.h" // for InputHandler
|
||||
#include "scene/scene_manager.h" // for SceneManager
|
||||
#include "shapes/shape.h" // for Shape (interfaz polimórfica)
|
||||
#include "shapes_mgr/shape_manager.h" // for ShapeManager
|
||||
#include "state/state_manager.h" // for StateManager
|
||||
#include "theme_manager.h" // for ThemeManager
|
||||
#include "ui/ui_manager.h" // for UIManager
|
||||
#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);
|
||||
bool initialize(int width = 0, int height = 0, int zoom = 0, bool fullscreen = false, AppMode initial_mode = AppMode::SANDBOX);
|
||||
void run();
|
||||
void shutdown();
|
||||
|
||||
@@ -49,7 +50,7 @@ class Engine {
|
||||
void toggleDepthZoom();
|
||||
|
||||
// Boids (comportamiento de enjambre)
|
||||
void toggleBoidsMode();
|
||||
void toggleBoidsMode(bool force_gravity_on = true);
|
||||
|
||||
// Temas de colores
|
||||
void cycleTheme(bool forward);
|
||||
@@ -105,6 +106,7 @@ class Engine {
|
||||
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;
|
||||
@@ -160,7 +162,6 @@ class Engine {
|
||||
// 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
|
||||
AppMode previous_app_mode_ = AppMode::SANDBOX; // 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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
#include "texture.h"
|
||||
#include "texture.hpp"
|
||||
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_log.h> // Para SDL_Log
|
||||
@@ -12,38 +12,7 @@
|
||||
#include <string> // Para operator<<, string
|
||||
|
||||
#include "stb_image.h" // Para stbi_failure_reason, stbi_image_free
|
||||
#include "../resource_pack.h" // Sistema de empaquetado de recursos
|
||||
|
||||
// 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;
|
||||
}
|
||||
#include "resource_manager.hpp" // Sistema de empaquetado de recursos centralizado
|
||||
|
||||
Texture::Texture(SDL_Renderer *renderer)
|
||||
: renderer_(renderer),
|
||||
@@ -70,30 +39,29 @@ bool Texture::loadFromFile(const std::string &file_path) {
|
||||
int width, height, orig_format;
|
||||
unsigned char *data = nullptr;
|
||||
|
||||
// 1. Intentar cargar desde pack (si está inicializado)
|
||||
if (g_resourcePack != nullptr) {
|
||||
ResourcePack::ResourceData packData = g_resourcePack->loadResource(file_path);
|
||||
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
|
||||
// 1. Intentar cargar desde ResourceManager (pack o disco)
|
||||
unsigned char* resourceData = nullptr;
|
||||
size_t resourceSize = 0;
|
||||
|
||||
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;
|
||||
} 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) {
|
||||
data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format);
|
||||
if (data == nullptr) {
|
||||
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;
|
||||
}
|
||||
SDL_Log("Error al cargar la imagen: %s", stbi_failure_reason());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int pitch;
|
||||
@@ -128,6 +96,9 @@ bool Texture::loadFromFile(const std::string &file_path) {
|
||||
|
||||
// Configurar filtro nearest neighbor para píxel perfect
|
||||
SDL_SetTextureScaleMode(new_texture, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
// Habilitar alpha blending para transparencias
|
||||
SDL_SetTextureBlendMode(new_texture, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
// Destruye la superficie cargada
|
||||
@@ -169,3 +140,17 @@ int Texture::getHeight() {
|
||||
void Texture::setColor(int r, int g, int 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_;
|
||||
|
||||
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
|
||||
explicit Texture(SDL_Renderer *renderer);
|
||||
Texture(SDL_Renderer *renderer, const std::string &file_path);
|
||||
@@ -44,6 +39,12 @@ class Texture {
|
||||
// Modula el color de la textura
|
||||
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
|
||||
SDL_Texture *getSDLTexture() const { return texture_; }
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "input_handler.h"
|
||||
#include "input_handler.hpp"
|
||||
|
||||
#include <SDL3/SDL_keycode.h> // for SDL_Keycode
|
||||
#include <string> // for std::string, std::to_string
|
||||
|
||||
#include "../engine.h" // for Engine
|
||||
#include "../external/mouse.h" // for Mouse namespace
|
||||
#include "engine.hpp" // for Engine
|
||||
#include "external/mouse.hpp" // for Mouse namespace
|
||||
|
||||
bool InputHandler::processEvents(Engine& engine) {
|
||||
SDL_Event event;
|
||||
|
||||
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);
|
||||
};
|
||||
@@ -1,6 +1,9 @@
|
||||
#include <iostream>
|
||||
#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
|
||||
|
||||
@@ -13,13 +16,17 @@ void printHelp() {
|
||||
std::cout << " -z, --zoom <n> Zoom de ventana (default: 3)\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 << " -m, --mode <mode> Modo inicial: sandbox, demo, demo-lite, logo (default: sandbox)\n";
|
||||
std::cout << " --help Mostrar esta ayuda\n\n";
|
||||
std::cout << "Ejemplos:\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 640 -h 480 -z 2 # 640x480 zoom 2 (ventana 1280x960)\n";
|
||||
std::cout << " vibe3_physics -f # Fullscreen letterbox (F3)\n";
|
||||
std::cout << " vibe3_physics -F # Fullscreen real (F4 - resolución nativa)\n\n";
|
||||
std::cout << " vibe3_physics -F # Fullscreen real (F4 - resolución nativa)\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";
|
||||
}
|
||||
|
||||
@@ -29,6 +36,7 @@ int main(int argc, char* argv[]) {
|
||||
int zoom = 0;
|
||||
bool fullscreen = false;
|
||||
bool real_fullscreen = false;
|
||||
AppMode initial_mode = AppMode::SANDBOX; // Modo inicial (default: SANDBOX)
|
||||
|
||||
// Parsear argumentos
|
||||
for (int i = 1; i < argc; i++) {
|
||||
@@ -38,8 +46,8 @@ int main(int argc, char* argv[]) {
|
||||
} else if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--width") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
width = atoi(argv[++i]);
|
||||
if (width < 640) {
|
||||
std::cerr << "Error: Ancho mínimo es 640px\n";
|
||||
if (width < 320) {
|
||||
std::cerr << "Error: Ancho mínimo es 320\n";
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -49,8 +57,8 @@ int main(int argc, char* argv[]) {
|
||||
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--height") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
height = atoi(argv[++i]);
|
||||
if (height < 480) {
|
||||
std::cerr << "Error: Alto mínimo es 480px\n";
|
||||
if (height < 240) {
|
||||
std::cerr << "Error: Alto mínimo es 240\n";
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
@@ -72,6 +80,25 @@ int main(int argc, char* argv[]) {
|
||||
fullscreen = true;
|
||||
} else if (strcmp(argv[i], "-F") == 0 || strcmp(argv[i], "--real-fullscreen") == 0) {
|
||||
real_fullscreen = 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 {
|
||||
std::cerr << "Error: Opción desconocida '" << argv[i] << "'\n";
|
||||
printHelp();
|
||||
@@ -82,11 +109,11 @@ int main(int argc, char* argv[]) {
|
||||
// Inicializar sistema de recursos empaquetados (intentar cargar resources.pack)
|
||||
std::string resources_dir = getResourcesDirectory();
|
||||
std::string pack_path = resources_dir + "/resources.pack";
|
||||
Texture::initResourceSystem(pack_path);
|
||||
ResourceManager::init(pack_path);
|
||||
|
||||
Engine engine;
|
||||
|
||||
if (!engine.initialize(width, height, zoom, fullscreen)) {
|
||||
if (!engine.initialize(width, height, zoom, fullscreen, initial_mode)) {
|
||||
std::cout << "¡Error al inicializar el engine!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
91
source/resource_manager.cpp
Normal file
91
source/resource_manager.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "resource_manager.hpp"
|
||||
#include "resource_pack.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
// Inicializar el puntero estático
|
||||
ResourcePack* ResourceManager::resourcePack_ = nullptr;
|
||||
|
||||
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() {
|
||||
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. Intentar cargar desde pack (si está disponible)
|
||||
if (resourcePack_ != nullptr) {
|
||||
ResourcePack::ResourceData packData = resourcePack_->loadResource(resourcePath);
|
||||
if (packData.data != nullptr) {
|
||||
data = packData.data;
|
||||
size = packData.size;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback: cargar desde disco
|
||||
std::ifstream file(resourcePath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
// Intentar con "data/" como prefijo si no se encontró
|
||||
std::string dataPath = "data/" + resourcePath;
|
||||
file.open(dataPath, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener tamaño del archivo
|
||||
size = static_cast<size_t>(file.tellg());
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
// Alocar buffer y leer
|
||||
data = new unsigned char[size];
|
||||
file.read(reinterpret_cast<char*>(data), size);
|
||||
file.close();
|
||||
|
||||
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;
|
||||
}
|
||||
82
source/resource_manager.hpp
Normal file
82
source/resource_manager.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#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_;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "resource_pack.h"
|
||||
#include "resource_pack.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#ifndef RESOURCE_PACK_H
|
||||
#define RESOURCE_PACK_H
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
@@ -64,5 +63,3 @@ private:
|
||||
uint32_t calculateChecksum(const unsigned char* data, size_t size);
|
||||
std::string normalizePath(const std::string& path);
|
||||
};
|
||||
|
||||
#endif // RESOURCE_PACK_H
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "scene_manager.h"
|
||||
#include "scene_manager.hpp"
|
||||
|
||||
#include <cstdlib> // for rand
|
||||
|
||||
#include "../defines.h" // for BALL_COUNT_SCENARIOS, GRAVITY_MASS_MIN, etc
|
||||
#include "../external/texture.h" // for Texture
|
||||
#include "../theme_manager.h" // for ThemeManager
|
||||
#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)
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <memory> // for unique_ptr, shared_ptr
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "../ball.h" // for Ball
|
||||
#include "../defines.h" // for GravityDirection
|
||||
#include "ball.hpp" // for Ball
|
||||
#include "defines.hpp" // for GravityDirection
|
||||
|
||||
// Forward declarations
|
||||
class Texture;
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "atom_shape.h"
|
||||
#include "../defines.h"
|
||||
#include "atom_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
#include <cmath>
|
||||
|
||||
void AtomShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.h"
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Átomo con núcleo central y órbitas electrónicas
|
||||
// Comportamiento: Núcleo estático + electrones orbitando en planos inclinados
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "cube_shape.h"
|
||||
#include "../defines.h"
|
||||
#include "cube_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
#include <cmath>
|
||||
|
||||
void CubeShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.h"
|
||||
#include "shape.hpp"
|
||||
#include <vector>
|
||||
|
||||
// Figura: Cubo 3D rotante
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "cylinder_shape.h"
|
||||
#include "../defines.h"
|
||||
#include "cylinder_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
#include <cmath>
|
||||
#include <cstdlib> // Para rand()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.h"
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Cilindro 3D rotante
|
||||
// Comportamiento: Superficie cilíndrica con rotación en eje Y + tumbling ocasional en X/Z
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "helix_shape.h"
|
||||
#include "../defines.h"
|
||||
#include "helix_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
#include <cmath>
|
||||
|
||||
void HelixShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.h"
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Espiral helicoidal 3D con distribución uniforme
|
||||
// Comportamiento: Rotación en eje Y + animación de fase vertical
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "icosahedron_shape.h"
|
||||
#include "../defines.h"
|
||||
#include "icosahedron_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.h"
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Icosaedro 3D (D20, poliedro regular de 20 caras)
|
||||
// Comportamiento: 12 vértices distribuidos uniformemente con rotación triple
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "lissajous_shape.h"
|
||||
#include "../defines.h"
|
||||
#include "lissajous_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
#include <cmath>
|
||||
|
||||
void LissajousShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.h"
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Curva de Lissajous 3D
|
||||
// Comportamiento: Curva paramétrica 3D con rotación global y animación de fase
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user