diff --git a/README.md b/README.md index a5c4c72..47fa835 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ El nombre refleja su proposito: **ViBe** (vibe-coding experimental) + **Physics* | `KP_+` | **Aumentar escala de figura (+10%)** | | `KP_-` | **Reducir escala de figura (-10%)** | | `KP_*` | **Reset escala de figura a 100%** | +| `KP_/` | **Toggle zoom por profundidad Z (perspectiva ON/OFF)** | ## 📊 Informacion en Pantalla @@ -147,10 +148,11 @@ Cuando se activa el debug display con la tecla `H`: - **Física de atracción**: Sistema spring-damper (Hooke's Law) para transición suave - **Profundidad Z simulada**: Color modulado según distancia (oscuro=fondo, brillante=frente) +- **Zoom por profundidad**: Perspectiva 3D con escala variable (50%-150% según Z) - **Z-sorting**: Painter's Algorithm para oclusión correcta - **Escala dinámica**: Control manual con Numpad +/- (30% - 300%) - **Protección de clipping**: Escala limitada automáticamente según resolución -- **Sin sprites adicionales**: Usa `SDL_SetTextureColorMod` para simular profundidad +- **Sin sprites adicionales**: Usa `SDL_SetTextureColorMod` y vértices escalados para efectos 3D ### Parámetros Físicos (defines.h) @@ -191,6 +193,7 @@ SHAPE_SCALE_STEP = 0.1f; // Incremento 10% - **Activación**: Presiona Q/W/E/R/T/Y/U/I para figura específica, o F para toggle - **Escala**: Usa Numpad +/- para ajustar tamaño, * para reset +- **Perspectiva**: Numpad / para activar/desactivar zoom por profundidad (ON por defecto) - **Salir**: G (sin gravedad), cursores (con gravedad), F (toggle), o 1-8 (cambiar escenario) - **Compatible**: Funciona con 1-100,000 pelotas - **Temas**: Mantiene paleta de colores activa diff --git a/source/ball.cpp b/source/ball.cpp index f76a7ec..21874a1 100644 --- a/source/ball.cpp +++ b/source/ball.cpp @@ -50,6 +50,7 @@ Ball::Ball(float x, float vx, float vy, Color color, std::shared_ptr te target_x_ = pos_.x; target_y_ = pos_.y; depth_brightness_ = 1.0f; + depth_scale_ = 1.0f; rotoball_attraction_active_ = false; } @@ -297,6 +298,10 @@ void Ball::setDepthBrightness(float brightness) { depth_brightness_ = brightness; } +void Ball::setDepthScale(float scale) { + depth_scale_ = scale; +} + // Activar/desactivar atracción física hacia esfera RotoBall void Ball::enableRotoBallAttraction(bool enable) { rotoball_attraction_active_ = enable; diff --git a/source/ball.h b/source/ball.h index 9ca4026..d9c23c3 100644 --- a/source/ball.h +++ b/source/ball.h @@ -27,6 +27,7 @@ class Ball { float pos_3d_x_, pos_3d_y_, pos_3d_z_; // Posición 3D en la esfera float target_x_, target_y_; // Posición destino 2D (proyección) float depth_brightness_; // Brillo según profundidad Z (0.0-1.0) + float depth_scale_; // Escala según profundidad Z (0.5-1.5) bool rotoball_attraction_active_; // ¿Está siendo atraída hacia la esfera? public: @@ -82,6 +83,8 @@ class Ball { void setRotoBallScreenPosition(float x, float y); // Establecer posición directa en pantalla void setDepthBrightness(float brightness); float getDepthBrightness() const { return depth_brightness_; } + void setDepthScale(float scale); + float getDepthScale() const { return depth_scale_; } // Sistema de atracción física hacia esfera RotoBall void enableRotoBallAttraction(bool enable); diff --git a/source/engine.cpp b/source/engine.cpp index 74ab845..31a24a0 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -346,6 +346,17 @@ void Engine::handleEvents() { } break; + case SDLK_KP_DIVIDE: + if (current_mode_ == SimulationMode::SHAPE) { + depth_zoom_enabled_ = !depth_zoom_enabled_; + text_ = depth_zoom_enabled_ ? "DEPTH ZOOM ON" : "DEPTH ZOOM OFF"; + int text_width = static_cast(text_.length() * 8); + text_pos_ = (current_screen_width_ - text_width) / 2; + text_init_time_ = SDL_GetTicks(); + show_text_ = true; + } + break; + case SDLK_1: scenario_ = 0; initBalls(scenario_); @@ -443,6 +454,7 @@ void Engine::render() { SDL_FRect pos = balls_[idx]->getPosition(); Color color = balls_[idx]->getColor(); float brightness = balls_[idx]->getDepthBrightness(); + float depth_scale = balls_[idx]->getDepthScale(); // Mapear brightness de 0-1 a rango MIN-MAX float brightness_factor = (ROTOBALL_MIN_BRIGHTNESS + brightness * @@ -453,14 +465,14 @@ void Engine::render() { int g_mod = static_cast(color.g * brightness_factor); int b_mod = static_cast(color.b * brightness_factor); - addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, r_mod, g_mod, b_mod); + addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, r_mod, g_mod, b_mod, depth_scale); } } else { - // MODO PHYSICS: Renderizar en orden normal del vector + // MODO PHYSICS: Renderizar en orden normal del vector (sin escala de profundidad) for (auto &ball : balls_) { SDL_FRect pos = ball->getPosition(); Color color = ball->getColor(); - addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, color.r, color.g, color.b); + addSpriteToBatch(pos.x, pos.y, pos.w, pos.h, color.r, color.g, color.b, 1.0f); } } @@ -774,7 +786,7 @@ void Engine::renderGradientBackground() { SDL_RenderGeometry(renderer_, nullptr, bg_vertices, 4, bg_indices, 6); } -void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b) { +void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale) { int vertex_index = static_cast(batch_vertices_.size()); // Crear 4 vértices para el quad (2 triángulos) @@ -785,23 +797,29 @@ void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g, float gf = g / 255.0f; float bf = b / 255.0f; + // Aplicar escala al tamaño (centrado en el punto x, y) + float scaled_w = w * scale; + float scaled_h = h * scale; + float offset_x = (w - scaled_w) / 2.0f; // Offset para centrar + float offset_y = (h - scaled_h) / 2.0f; + // Vértice superior izquierdo - vertices[0].position = {x, y}; + vertices[0].position = {x + offset_x, y + offset_y}; vertices[0].tex_coord = {0.0f, 0.0f}; vertices[0].color = {rf, gf, bf, 1.0f}; // Vértice superior derecho - vertices[1].position = {x + w, y}; + vertices[1].position = {x + offset_x + scaled_w, y + offset_y}; vertices[1].tex_coord = {1.0f, 0.0f}; vertices[1].color = {rf, gf, bf, 1.0f}; // Vértice inferior derecho - vertices[2].position = {x + w, y + h}; + vertices[2].position = {x + offset_x + scaled_w, y + offset_y + scaled_h}; vertices[2].tex_coord = {1.0f, 1.0f}; vertices[2].color = {rf, gf, bf, 1.0f}; // Vértice inferior izquierdo - vertices[3].position = {x, y + h}; + vertices[3].position = {x + offset_x, y + offset_y + scaled_h}; vertices[3].tex_coord = {0.0f, 1.0f}; vertices[3].color = {rf, gf, bf, 1.0f}; @@ -1010,9 +1028,10 @@ void Engine::toggleShapeMode(bool force_gravity_on_exit) { // Volver a modo física normal current_mode_ = SimulationMode::PHYSICS; - // Desactivar atracción - las pelotas conservan su velocidad tangencial actual + // Desactivar atracción y resetear escala de profundidad for (auto& ball : balls_) { ball->enableRotoBallAttraction(false); + ball->setDepthScale(1.0f); // Reset escala a 100% (evita "pop" visual) } // Activar gravedad al salir (solo si se especifica) @@ -1120,6 +1139,11 @@ void Engine::updateShape() { float z_normalized = (z_3d + shape_size) / (2.0f * shape_size); z_normalized = std::max(0.0f, std::min(1.0f, z_normalized)); balls_[i]->setDepthBrightness(z_normalized); + + // Calcular escala según profundidad Z (perspectiva) - solo si está activado + // 0.0 (fondo) → 0.5x, 0.5 (medio) → 1.0x, 1.0 (frente) → 1.5x + float depth_scale = depth_zoom_enabled_ ? (0.5f + z_normalized * 1.0f) : 1.0f; + balls_[i]->setDepthScale(depth_scale); } } diff --git a/source/engine.h b/source/engine.h index 41ba02d..f9d0e3f 100644 --- a/source/engine.h +++ b/source/engine.h @@ -87,6 +87,7 @@ private: ShapeType last_shape_type_ = ShapeType::SPHERE; // Última figura para toggle F std::unique_ptr active_shape_; // Puntero polimórfico a figura activa float shape_scale_factor_ = 1.0f; // Factor de escala manual (Numpad +/-) + bool depth_zoom_enabled_ = true; // Zoom por profundidad Z activado // Batch rendering std::vector batch_vertices_; @@ -123,7 +124,7 @@ private: // Rendering void renderGradientBackground(); - void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b); + void addSpriteToBatch(float x, float y, float w, float h, int r, int g, int b, float scale = 1.0f); // Sistema de Figuras 3D void toggleShapeMode(bool force_gravity_on_exit = true); // Toggle PHYSICS ↔ última figura (tecla F)