From 91f8bfdd3086b3b460e38beee5970fff20439a6f Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 3 Oct 2025 21:00:19 +0200 Subject: [PATCH] Implementar zoom por profundidad Z con perspectiva 3D + toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NUEVAS CARACTERÍSTICAS: - Zoom por profundidad Z: Escala sprites según distancia (0.5x-1.5x) - Toggle con Numpad / (KP_DIVIDE) para activar/desactivar perspectiva - Fix transición figura→física: Reset automático de depth_scale a 1.0 - Texto informativo: "DEPTH ZOOM ON/OFF" IMPLEMENTACIÓN TÉCNICA: - Ball class: Nueva variable depth_scale_ (0.5-1.5) - Ball class: Getters/setters getDepthScale() / setDepthScale() - Engine::addSpriteToBatch(): Parámetro scale con valor defecto 1.0 - Engine::addSpriteToBatch(): Cálculo de vértices escalados centrados - Engine::updateShape(): Cálculo depth_scale = 0.5 + z_normalized * 1.0 - Engine::render(): Pasa depth_scale al batch en modo SHAPE - Engine::toggleShapeMode(): Reset depth_scale en salida de figura - Engine: Variable depth_zoom_enabled_ (true por defecto) - Batch rendering: Mantiene performance (sin llamadas individuales) EFECTO VISUAL: - Pelotas lejanas (Z-): Pequeñas (50%) y oscuras - Pelotas medias (Z=0): Normales (100%) y brillo medio - Pelotas cercanas (Z+): Grandes (150%) y brillantes - Perspectiva 3D realista combinada con Z-sorting CONTROLES: - Numpad /: Toggle zoom por profundidad (solo en modo SHAPE) - Por defecto: ACTIVADO para máximo realismo 3D README ACTUALIZADO: - Añadida tecla KP_/ a tabla de controles - Actualizada sección "Características Técnicas" - Añadida línea "Zoom por profundidad" en características - Actualizada sección "Uso" con control de perspectiva 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 5 ++++- source/ball.cpp | 5 +++++ source/ball.h | 3 +++ source/engine.cpp | 42 +++++++++++++++++++++++++++++++++--------- source/engine.h | 3 ++- 5 files changed, 47 insertions(+), 11 deletions(-) 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)