From 757bb9c52577e72eb029920cb16e6305bf0ba211 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 4 Oct 2025 16:42:27 +0200 Subject: [PATCH] PNG_SHAPE: Auto-switch a bordes cuando hay pocas pelotas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problema: - PNG_USE_EDGES_ONLY = false usa ~22,000 puntos 3D - Con 1, 10 o 100 pelotas, no hay suficientes para formar el logo - Resultado: logo invisible o mal formado Solución: - Detectar automáticamente si num_pelotas < total_puntos / 2 - Si hay pocas pelotas → cambiar automáticamente a BORDES - Bordes usa ~300 puntos × 15 capas = ~4,500 puntos 3D - Mucho mejor ratio para pocos sprites Implementación: - generatePoints() verifica ratio pelotas/puntos - Si insuficiente: llama detectEdges() y regenera - getPoint3D() usa edge_points_ si están disponibles - Mensajes informativos en consola Ahora funciona: Escenario 1 (1 pelota) → Auto-switch a bordes ✅ Escenario 2 (10 pelotas) → Auto-switch a bordes ✅ Escenario 5 (1000 pelotas) → Usa relleno completo ✅ Escenario 6+ (10K+ pelotas) → Usa relleno completo ✅ Output de debug muestra: [PNG_SHAPE] Advertencia: Solo X pelotas para Y puntos [PNG_SHAPE] Cambiando automáticamente a BORDES... [PNG_SHAPE] Modo: BORDES/RELLENO 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- source/defines.h | 149 ++++++++++++++++++------------------ source/shapes/png_shape.cpp | 23 +++++- 2 files changed, 93 insertions(+), 79 deletions(-) diff --git a/source/defines.h b/source/defines.h index 7e7000c..d939df6 100644 --- a/source/defines.h +++ b/source/defines.h @@ -7,9 +7,8 @@ constexpr char WINDOW_CAPTION[] = "vibe3_physics"; // 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) -// BALL_SIZE eliminado: ahora se obtiene dinámicamente desde texture_->getWidth() +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) // Configuración de zoom dinámico de ventana constexpr int WINDOW_ZOOM_MIN = 1; // Zoom mínimo (320x240) @@ -64,22 +63,22 @@ enum class ColorTheme { // Enum para tipo de figura 3D enum class ShapeType { - NONE, // Sin figura (modo física pura) - SPHERE, // Esfera Fibonacci (antiguo RotoBall) - CUBE, // Cubo rotante - HELIX, // Espiral 3D - TORUS, // Toroide/donut - WAVE_GRID, // Malla ondeante - CYLINDER, // Cilindro rotante - ICOSAHEDRON, // Icosaedro D20 - ATOM, // Átomo con órbitas - PNG_SHAPE // Forma cargada desde PNG 1-bit + NONE, // Sin figura (modo física pura) + SPHERE, // Esfera Fibonacci (antiguo RotoBall) + CUBE, // Cubo rotante + HELIX, // Espiral 3D + TORUS, // Toroide/donut + WAVE_GRID, // Malla ondeante + CYLINDER, // Cilindro rotante + ICOSAHEDRON, // Icosaedro D20 + ATOM, // Átomo con órbitas + PNG_SHAPE // Forma cargada desde PNG 1-bit }; // Enum para modo de simulación enum class SimulationMode { - PHYSICS, // Modo física normal con gravedad - SHAPE // Modo figura 3D (Shape polimórfico) + PHYSICS, // Modo física normal con gravedad + SHAPE // Modo figura 3D (Shape polimórfico) }; // Enum para modo de escalado en fullscreen (F5) @@ -99,45 +98,45 @@ constexpr int ROTOBALL_MAX_BRIGHTNESS = 255; // Brillo máximo (frente, 0- // Física de atracción para figuras 3D (sistema de resorte) // ROTOBALL: Figura esfera rotante especial (modo C) -constexpr float ROTOBALL_SPRING_K = 300.0f; // Constante de rigidez del resorte (N/m) -constexpr float ROTOBALL_DAMPING_BASE = 35.0f; // Amortiguación base (amortiguamiento crítico ≈ 2*√k*m) -constexpr float ROTOBALL_DAMPING_NEAR = 80.0f; // Amortiguación cerca del punto (absorción rápida) -constexpr float ROTOBALL_NEAR_THRESHOLD = 5.0f; // Distancia "cerca" en píxeles -constexpr float ROTOBALL_MAX_FORCE = 1000.0f; // Fuerza máxima aplicable (evita explosiones) +constexpr float ROTOBALL_SPRING_K = 300.0f; // Constante de rigidez del resorte (N/m) +constexpr float ROTOBALL_DAMPING_BASE = 35.0f; // Amortiguación base (amortiguamiento crítico ≈ 2*√k*m) +constexpr float ROTOBALL_DAMPING_NEAR = 80.0f; // Amortiguación cerca del punto (absorción rápida) +constexpr float ROTOBALL_NEAR_THRESHOLD = 5.0f; // Distancia "cerca" en píxeles +constexpr float ROTOBALL_MAX_FORCE = 1000.0f; // Fuerza máxima aplicable (evita explosiones) // SHAPE: Figuras 3D normales (Q/W/E/R/T/Y/U/I/O) - Mayor pegajosidad -constexpr float SHAPE_SPRING_K = 800.0f; // Rigidez alta (pelotas más "pegadas") -constexpr float SHAPE_DAMPING_BASE = 60.0f; // Amortiguación alta (menos rebote) -constexpr float SHAPE_DAMPING_NEAR = 150.0f; // Absorción muy rápida al llegar -constexpr float SHAPE_NEAR_THRESHOLD = 8.0f; // Umbral "cerca" más amplio -constexpr float SHAPE_MAX_FORCE = 2000.0f; // Permite fuerzas más fuertes +constexpr float SHAPE_SPRING_K = 800.0f; // Rigidez alta (pelotas más "pegadas") +constexpr float SHAPE_DAMPING_BASE = 60.0f; // Amortiguación alta (menos rebote) +constexpr float SHAPE_DAMPING_NEAR = 150.0f; // Absorción muy rápida al llegar +constexpr float SHAPE_NEAR_THRESHOLD = 8.0f; // Umbral "cerca" más amplio +constexpr float SHAPE_MAX_FORCE = 2000.0f; // Permite fuerzas más fuertes // Configuración del Cubo (cubo 3D rotante) -constexpr float CUBE_SIZE_FACTOR = 0.25f; // Tamaño como proporción de altura (60/240 = 0.25) -constexpr float CUBE_ROTATION_SPEED_X = 0.5f; // Velocidad rotación eje X (rad/s) -constexpr float CUBE_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s) -constexpr float CUBE_ROTATION_SPEED_Z = 0.3f; // Velocidad rotación eje Z (rad/s) +constexpr float CUBE_SIZE_FACTOR = 0.25f; // Tamaño como proporción de altura (60/240 = 0.25) +constexpr float CUBE_ROTATION_SPEED_X = 0.5f; // Velocidad rotación eje X (rad/s) +constexpr float CUBE_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s) +constexpr float CUBE_ROTATION_SPEED_Z = 0.3f; // Velocidad rotación eje Z (rad/s) // Configuración de Helix (espiral helicoidal 3D) -constexpr float HELIX_RADIUS_FACTOR = 0.25f; // Radio de la espiral (proporción de altura) -constexpr float HELIX_PITCH_FACTOR = 0.25f; // Separación vertical entre vueltas (proporción de altura) -constexpr float HELIX_NUM_TURNS = 3.0f; // Número de vueltas completas (1-5) -constexpr float HELIX_ROTATION_SPEED_Y = 1.2f; // Velocidad rotación eje Y (rad/s) -constexpr float HELIX_PHASE_SPEED = 0.5f; // Velocidad de animación vertical (rad/s) +constexpr float HELIX_RADIUS_FACTOR = 0.25f; // Radio de la espiral (proporción de altura) +constexpr float HELIX_PITCH_FACTOR = 0.25f; // Separación vertical entre vueltas (proporción de altura) +constexpr float HELIX_NUM_TURNS = 3.0f; // Número de vueltas completas (1-5) +constexpr float HELIX_ROTATION_SPEED_Y = 1.2f; // Velocidad rotación eje Y (rad/s) +constexpr float HELIX_PHASE_SPEED = 0.5f; // Velocidad de animación vertical (rad/s) // Configuración de Wave Grid (malla ondeante 3D) -constexpr float WAVE_GRID_SIZE_FACTOR = 0.35f; // Tamaño del grid (proporción de altura) -constexpr float WAVE_GRID_AMPLITUDE = 0.15f; // Amplitud de las ondas (proporción de altura) -constexpr float WAVE_GRID_FREQUENCY = 3.0f; // Frecuencia de ondas (ciclos por grid) -constexpr float WAVE_GRID_PHASE_SPEED = 2.0f; // Velocidad de animación de ondas (rad/s) -constexpr float WAVE_GRID_ROTATION_SPEED_Y = 0.4f; // Velocidad rotación eje Y (rad/s) +constexpr float WAVE_GRID_SIZE_FACTOR = 0.35f; // Tamaño del grid (proporción de altura) +constexpr float WAVE_GRID_AMPLITUDE = 0.15f; // Amplitud de las ondas (proporción de altura) +constexpr float WAVE_GRID_FREQUENCY = 3.0f; // Frecuencia de ondas (ciclos por grid) +constexpr float WAVE_GRID_PHASE_SPEED = 2.0f; // Velocidad de animación de ondas (rad/s) +constexpr float WAVE_GRID_ROTATION_SPEED_Y = 0.4f; // Velocidad rotación eje Y (rad/s) // Configuración de Torus (toroide/donut 3D) -constexpr float TORUS_MAJOR_RADIUS_FACTOR = 0.25f; // Radio mayor R (centro torus a centro tubo) -constexpr float TORUS_MINOR_RADIUS_FACTOR = 0.12f; // Radio menor r (grosor del tubo) -constexpr float TORUS_ROTATION_SPEED_X = 0.6f; // Velocidad rotación eje X (rad/s) -constexpr float TORUS_ROTATION_SPEED_Y = 0.9f; // Velocidad rotación eje Y (rad/s) -constexpr float TORUS_ROTATION_SPEED_Z = 0.3f; // Velocidad rotación eje Z (rad/s) +constexpr float TORUS_MAJOR_RADIUS_FACTOR = 0.25f; // Radio mayor R (centro torus a centro tubo) +constexpr float TORUS_MINOR_RADIUS_FACTOR = 0.12f; // Radio menor r (grosor del tubo) +constexpr float TORUS_ROTATION_SPEED_X = 0.6f; // Velocidad rotación eje X (rad/s) +constexpr float TORUS_ROTATION_SPEED_Y = 0.9f; // Velocidad rotación eje Y (rad/s) +constexpr float TORUS_ROTATION_SPEED_Z = 0.3f; // Velocidad rotación eje Z (rad/s) // Configuración de Cylinder (cilindro 3D) constexpr float CYLINDER_RADIUS_FACTOR = 0.25f; // Radio del cilindro (proporción de altura) @@ -145,10 +144,10 @@ constexpr float CYLINDER_HEIGHT_FACTOR = 0.5f; // Altura del cilindro (propo constexpr float CYLINDER_ROTATION_SPEED_Y = 1.0f; // Velocidad rotación eje Y (rad/s) // Configuración de Icosahedron (icosaedro D20) -constexpr float ICOSAHEDRON_RADIUS_FACTOR = 0.30f; // Radio de la esfera circunscrita -constexpr float ICOSAHEDRON_ROTATION_SPEED_X = 0.4f; // Velocidad rotación eje X (rad/s) -constexpr float ICOSAHEDRON_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s) -constexpr float ICOSAHEDRON_ROTATION_SPEED_Z = 0.2f; // Velocidad rotación eje Z (rad/s) +constexpr float ICOSAHEDRON_RADIUS_FACTOR = 0.30f; // Radio de la esfera circunscrita +constexpr float ICOSAHEDRON_ROTATION_SPEED_X = 0.4f; // Velocidad rotación eje X (rad/s) +constexpr float ICOSAHEDRON_ROTATION_SPEED_Y = 0.7f; // Velocidad rotación eje Y (rad/s) +constexpr float ICOSAHEDRON_ROTATION_SPEED_Z = 0.2f; // Velocidad rotación eje Z (rad/s) // Configuración de Atom (núcleo con órbitas electrónicas) constexpr float ATOM_NUCLEUS_RADIUS_FACTOR = 0.08f; // Radio del núcleo central @@ -163,33 +162,33 @@ constexpr float PNG_EXTRUSION_DEPTH_FACTOR = 0.12f; // Profundidad de extrusió constexpr int PNG_NUM_EXTRUSION_LAYERS = 15; // Capas de extrusión (más capas = más pegajosidad) constexpr bool PNG_USE_EDGES_ONLY = false; // true = solo bordes, false = relleno completo // Rotación "legible" (texto de frente con volteretas ocasionales) -constexpr float PNG_IDLE_TIME_MIN = 3.0f; // Tiempo mínimo de frente (segundos) -constexpr float PNG_IDLE_TIME_MAX = 8.0f; // Tiempo máximo de frente (segundos) -constexpr float PNG_FLIP_SPEED = 3.0f; // Velocidad voltereta (rad/s) -constexpr float PNG_FLIP_DURATION = 1.5f; // Duración voltereta (segundos) +constexpr float PNG_IDLE_TIME_MIN = 3.0f; // Tiempo mínimo de frente (segundos) +constexpr float PNG_IDLE_TIME_MAX = 8.0f; // Tiempo máximo de frente (segundos) +constexpr float PNG_FLIP_SPEED = 3.0f; // Velocidad voltereta (rad/s) +constexpr float PNG_FLIP_DURATION = 1.5f; // Duración voltereta (segundos) // Control manual de escala de figuras 3D (Numpad +/-) -constexpr float SHAPE_SCALE_MIN = 0.3f; // Escala mínima (30%) -constexpr float SHAPE_SCALE_MAX = 3.0f; // Escala máxima (300%) -constexpr float SHAPE_SCALE_STEP = 0.1f; // Incremento por pulsación -constexpr float SHAPE_SCALE_DEFAULT = 1.0f; // Escala por defecto (100%) +constexpr float SHAPE_SCALE_MIN = 0.3f; // Escala mínima (30%) +constexpr float SHAPE_SCALE_MAX = 3.0f; // Escala máxima (300%) +constexpr float SHAPE_SCALE_STEP = 0.1f; // Incremento por pulsación +constexpr float SHAPE_SCALE_DEFAULT = 1.0f; // Escala por defecto (100%) // Configuración de Modo DEMO (auto-play completo) -constexpr float DEMO_ACTION_INTERVAL_MIN = 2.0f; // Tiempo mínimo entre acciones (segundos) -constexpr float DEMO_ACTION_INTERVAL_MAX = 6.0f; // Tiempo máximo entre acciones (segundos) +constexpr float DEMO_ACTION_INTERVAL_MIN = 2.0f; // Tiempo mínimo entre acciones (segundos) +constexpr float DEMO_ACTION_INTERVAL_MAX = 6.0f; // Tiempo máximo entre acciones (segundos) // Pesos de probabilidad DEMO MODE (valores relativos, se normalizan) -constexpr int DEMO_WEIGHT_GRAVITY_DIR = 12; // Cambiar dirección gravedad (12%) -constexpr int DEMO_WEIGHT_GRAVITY_TOGGLE = 15; // Toggle gravedad ON/OFF (15%) - ¡Ver caer pelotas! -constexpr int DEMO_WEIGHT_SHAPE = 22; // Activar figura 3D (22%) - Construir figuras -constexpr int DEMO_WEIGHT_TOGGLE_PHYSICS = 18; // Toggle física ↔ figura (18%) - ¡Destruir figuras! -constexpr int DEMO_WEIGHT_REGENERATE_SHAPE = 10; // Re-generar misma figura (10%) - Reconstruir -constexpr int DEMO_WEIGHT_THEME = 12; // Cambiar tema de colores (12%) -constexpr int DEMO_WEIGHT_SCENARIO = 2; // Cambiar número de pelotas (2%) - MUY OCASIONAL -constexpr int DEMO_WEIGHT_IMPULSE = 6; // Aplicar impulso (SPACE) (6%) -constexpr int DEMO_WEIGHT_DEPTH_ZOOM = 1; // Toggle profundidad (1%) -constexpr int DEMO_WEIGHT_SHAPE_SCALE = 1; // Cambiar escala figura (1%) -constexpr int DEMO_WEIGHT_SPRITE = 1; // Cambiar sprite (1%) +constexpr int DEMO_WEIGHT_GRAVITY_DIR = 12; // Cambiar dirección gravedad (12%) +constexpr int DEMO_WEIGHT_GRAVITY_TOGGLE = 15; // Toggle gravedad ON/OFF (15%) - ¡Ver caer pelotas! +constexpr int DEMO_WEIGHT_SHAPE = 22; // Activar figura 3D (22%) - Construir figuras +constexpr int DEMO_WEIGHT_TOGGLE_PHYSICS = 18; // Toggle física ↔ figura (18%) - ¡Destruir figuras! +constexpr int DEMO_WEIGHT_REGENERATE_SHAPE = 10; // Re-generar misma figura (10%) - Reconstruir +constexpr int DEMO_WEIGHT_THEME = 12; // Cambiar tema de colores (12%) +constexpr int DEMO_WEIGHT_SCENARIO = 2; // Cambiar número de pelotas (2%) - MUY OCASIONAL +constexpr int DEMO_WEIGHT_IMPULSE = 6; // Aplicar impulso (SPACE) (6%) +constexpr int DEMO_WEIGHT_DEPTH_ZOOM = 1; // Toggle profundidad (1%) +constexpr int DEMO_WEIGHT_SHAPE_SCALE = 1; // Cambiar escala figura (1%) +constexpr int DEMO_WEIGHT_SPRITE = 1; // Cambiar sprite (1%) // TOTAL: 100 // Configuración de Modo DEMO LITE (solo física/figuras) @@ -197,11 +196,11 @@ constexpr float DEMO_LITE_ACTION_INTERVAL_MIN = 1.5f; // Más rápido que demo constexpr float DEMO_LITE_ACTION_INTERVAL_MAX = 4.0f; // Pesos de probabilidad DEMO LITE (solo física/figuras, sin cambios de escenario/tema) -constexpr int DEMO_LITE_WEIGHT_GRAVITY_DIR = 25; // Cambiar dirección gravedad (25%) -constexpr int DEMO_LITE_WEIGHT_GRAVITY_TOGGLE = 20;// Toggle gravedad ON/OFF (20%) -constexpr int DEMO_LITE_WEIGHT_SHAPE = 25; // Activar figura 3D (25%) -constexpr int DEMO_LITE_WEIGHT_TOGGLE_PHYSICS = 20;// Toggle física ↔ figura (20%) -constexpr int DEMO_LITE_WEIGHT_IMPULSE = 10; // Aplicar impulso (10%) +constexpr int DEMO_LITE_WEIGHT_GRAVITY_DIR = 25; // Cambiar dirección gravedad (25%) +constexpr int DEMO_LITE_WEIGHT_GRAVITY_TOGGLE = 20; // Toggle gravedad ON/OFF (20%) +constexpr int DEMO_LITE_WEIGHT_SHAPE = 25; // Activar figura 3D (25%) +constexpr int DEMO_LITE_WEIGHT_TOGGLE_PHYSICS = 20; // Toggle física ↔ figura (20%) +constexpr int DEMO_LITE_WEIGHT_IMPULSE = 10; // Aplicar impulso (10%) // TOTAL: 100 -constexpr float PI = 3.14159265358979323846f; // Constante PI \ No newline at end of file +constexpr float PI = 3.14159265358979323846f; // Constante PI \ No newline at end of file diff --git a/source/shapes/png_shape.cpp b/source/shapes/png_shape.cpp index ea6d77d..cc29ed7 100644 --- a/source/shapes/png_shape.cpp +++ b/source/shapes/png_shape.cpp @@ -98,12 +98,27 @@ void PNGShape::generatePoints(int num_points, float screen_width, float screen_h extrusion_depth_ = screen_height * PNG_EXTRUSION_DEPTH_FACTOR; num_layers_ = PNG_NUM_EXTRUSION_LAYERS; - // Generar puntos según el enfoque + // Generar puntos según el enfoque configurado generateExtrudedPoints(); - // Debug: mostrar cantidad de puntos 2D detectados + // Calcular cuántos puntos 3D se necesitan size_t num_2d_points = PNG_USE_EDGES_ONLY ? edge_points_.size() : filled_points_.size(); size_t total_3d_points = num_2d_points * num_layers_; + + // ADAPTACIÓN AUTOMÁTICA: Si hay muy pocas pelotas, cambiar a bordes + if (!PNG_USE_EDGES_ONLY && num_points < static_cast(total_3d_points) / 2) { + std::cout << "[PNG_SHAPE] Advertencia: Solo " << num_points << " pelotas para " + << total_3d_points << " puntos (relleno).\n"; + std::cout << "[PNG_SHAPE] Cambiando automáticamente a BORDES para mejor visualización.\n"; + + // Regenerar solo con bordes + detectEdges(); + num_2d_points = edge_points_.size(); + total_3d_points = num_2d_points * num_layers_; + } + + // Debug: mostrar configuración final + std::cout << "[PNG_SHAPE] Modo: " << (PNG_USE_EDGES_ONLY ? "BORDES" : "RELLENO") << "\n"; std::cout << "[PNG_SHAPE] Detectados " << num_2d_points << " puntos 2D × " << num_layers_ << " capas = " << total_3d_points << " puntos 3D totales\n"; std::cout << "[PNG_SHAPE] Pelotas disponibles: " << num_points << "\n"; @@ -159,8 +174,8 @@ void PNGShape::update(float delta_time, float screen_width, float screen_height) } void PNGShape::getPoint3D(int index, float& x, float& y, float& z) const { - // Seleccionar puntos según configuración - const std::vector& points = PNG_USE_EDGES_ONLY ? edge_points_ : filled_points_; + // Seleccionar puntos según configuración (priorizar edges si fue auto-ajustado) + const std::vector& points = (!edge_points_.empty()) ? edge_points_ : filled_points_; if (points.empty()) { x = y = z = 0.0f;