diff --git a/source/defines.h b/source/defines.h index d31fc34..7fbc2df 100644 --- a/source/defines.h +++ b/source/defines.h @@ -121,6 +121,11 @@ constexpr float TORUS_ROTATION_SPEED_X = 0.6f; // Velocidad rotación eje X 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) +constexpr float CYLINDER_HEIGHT_FACTOR = 0.5f; // Altura del cilindro (proporción de altura) +constexpr float CYLINDER_ROTATION_SPEED_Y = 1.0f; // Velocidad rotación eje Y (rad/s) + // 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%) diff --git a/source/engine.cpp b/source/engine.cpp index 2e2bdd5..a68b00f 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -28,6 +28,7 @@ #include "shapes/helix_shape.h" // for HelixShape #include "shapes/wave_grid_shape.h" // for WaveGridShape #include "shapes/torus_shape.h" // for TorusShape +#include "shapes/cylinder_shape.h" // for CylinderShape // Función auxiliar para obtener la ruta del directorio del ejecutable std::string getExecutableDirectory() { @@ -1080,6 +1081,9 @@ void Engine::activateShape(ShapeType type) { case ShapeType::WAVE_GRID: active_shape_ = std::make_unique(); break; + case ShapeType::CYLINDER: + active_shape_ = std::make_unique(); + break; // Futuras figuras se añadirán aquí default: active_shape_ = std::make_unique(); // Fallback diff --git a/source/shapes/cylinder_shape.cpp b/source/shapes/cylinder_shape.cpp new file mode 100644 index 0000000..7988655 --- /dev/null +++ b/source/shapes/cylinder_shape.cpp @@ -0,0 +1,77 @@ +#include "cylinder_shape.h" +#include "../defines.h" +#include + +void CylinderShape::generatePoints(int num_points, float screen_width, float screen_height) { + num_points_ = num_points; + radius_ = screen_height * CYLINDER_RADIUS_FACTOR; + height_ = screen_height * CYLINDER_HEIGHT_FACTOR; + // Las posiciones 3D se calculan en getPoint3D() usando ecuaciones paramétricas del cilindro +} + +void CylinderShape::update(float delta_time, float screen_width, float screen_height) { + // Recalcular dimensiones por si cambió resolución (F4) + radius_ = screen_height * CYLINDER_RADIUS_FACTOR; + height_ = screen_height * CYLINDER_HEIGHT_FACTOR; + + // Actualizar ángulo de rotación en eje Y + angle_y_ += CYLINDER_ROTATION_SPEED_Y * delta_time; +} + +void CylinderShape::getPoint3D(int index, float& x, float& y, float& z) const { + // Distribuir puntos uniformemente en la superficie del cilindro + // Calcular número de anillos (altura) y puntos por anillo (circunferencia) + + int num_rings = static_cast(sqrtf(static_cast(num_points_) * 0.5f)); + if (num_rings < 2) num_rings = 2; + + int points_per_ring = num_points_ / num_rings; + if (points_per_ring < 3) points_per_ring = 3; + + // Obtener parámetros u (ángulo) y v (altura) del índice + int ring = index / points_per_ring; + int point_in_ring = index % points_per_ring; + + // Si nos pasamos del número de anillos, usar el último + if (ring >= num_rings) { + ring = num_rings - 1; + point_in_ring = index - (ring * points_per_ring); + if (point_in_ring >= points_per_ring) { + point_in_ring = points_per_ring - 1; + } + } + + // Parámetro u (ángulo alrededor del cilindro): [0, 2π] + float u = (static_cast(point_in_ring) / static_cast(points_per_ring)) * 2.0f * PI; + + // Parámetro v (altura normalizada): [-1, 1] + float v = (static_cast(ring) / static_cast(num_rings - 1)) * 2.0f - 1.0f; + if (num_rings == 1) v = 0.0f; + + // Ecuaciones paramétricas del cilindro + // x = radius * cos(u) + // y = height * v + // z = radius * sin(u) + float x_base = radius_ * cosf(u); + float y_base = (height_ * 0.5f) * v; // Centrar verticalmente + float z_base = radius_ * sinf(u); + + // Aplicar rotación en eje Y + float cos_y = cosf(angle_y_); + float sin_y = sinf(angle_y_); + float x_rot = x_base * cos_y - z_base * sin_y; + float z_rot = x_base * sin_y + z_base * cos_y; + + // Retornar coordenadas finales rotadas + x = x_rot; + y = y_base; + z = z_rot; +} + +float CylinderShape::getScaleFactor(float screen_height) const { + // Factor de escala para física: proporcional a la dimensión mayor (altura) + // Altura base = 120px (0.5 * 240px en resolución 320x240) + const float BASE_HEIGHT = 120.0f; + float current_height = screen_height * CYLINDER_HEIGHT_FACTOR; + return current_height / BASE_HEIGHT; +} diff --git a/source/shapes/cylinder_shape.h b/source/shapes/cylinder_shape.h new file mode 100644 index 0000000..277c572 --- /dev/null +++ b/source/shapes/cylinder_shape.h @@ -0,0 +1,21 @@ +#pragma once + +#include "shape.h" + +// Figura: Cilindro 3D rotante +// Comportamiento: Superficie cilíndrica con rotación en eje Y +// Ecuaciones: x = r*cos(u), y = v, z = r*sin(u) +class CylinderShape : public Shape { +private: + float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad) + float radius_ = 0.0f; // Radio del cilindro (píxeles) + float height_ = 0.0f; // Altura del cilindro (píxeles) + int num_points_ = 0; // Cantidad de puntos generados + +public: + void generatePoints(int num_points, float screen_width, float screen_height) override; + void update(float delta_time, float screen_width, float screen_height) override; + void getPoint3D(int index, float& x, float& y, float& z) const override; + const char* getName() const override { return "CYLINDER"; } + float getScaleFactor(float screen_height) const override; +};