style: aplicar fixes de clang-tidy (todo excepto uppercase-literal-suffix)
Corregidos ~2570 issues automáticamente con clang-tidy --fix-errors más ajustes manuales posteriores: - modernize: designated-initializers, trailing-return-type, use-auto, avoid-c-arrays (→ std::array<>), use-ranges, use-emplace, deprecated-headers, use-equals-default, pass-by-value, return-braced-init-list, use-default-member-init - readability: math-missing-parentheses, implicit-bool-conversion, braces-around-statements, isolate-declaration, use-std-min-max, identifier-naming, else-after-return, redundant-casting, convert-member-functions-to-static, make-member-function-const, static-accessed-through-instance - performance: avoid-endl, unnecessary-value-param, type-promotion, inefficient-vector-operation - dead code: XOR_KEY (orphan tras eliminar encryptData/decryptData), dead stores en engine.cpp y png_shape.cpp - NOLINT justificado en 10 funciones con alta complejidad cognitiva (initialize, render, main, processEvents, update×3, performDemoAction, randomizeOnDemoStart, renderDebugHUD, AppLogo::update) Compilación: gcc -Wall sin warnings. clang-tidy: 0 issues. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
#include "atom_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void AtomShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
nucleus_radius_ = screen_height * ATOM_NUCLEUS_RADIUS_FACTOR;
|
||||
@@ -25,15 +28,15 @@ void AtomShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
int num_orbits = static_cast<int>(ATOM_NUM_ORBITS);
|
||||
|
||||
// Calcular cuántos puntos para núcleo vs órbitas
|
||||
int nucleus_points = (num_points_ < 10) ? 1 : (num_points_ / 10); // 10% para núcleo
|
||||
if (nucleus_points < 1) nucleus_points = 1;
|
||||
int nucleus_points = (num_points_ < 10) ? 1 : (num_points_ / 10); // 10% para núcleo
|
||||
nucleus_points = std::max(nucleus_points, 1);
|
||||
|
||||
// Si estamos en el núcleo
|
||||
if (index < nucleus_points) {
|
||||
// Distribuir puntos en esfera pequeña (núcleo)
|
||||
float t = static_cast<float>(index) / static_cast<float>(nucleus_points);
|
||||
float phi = acosf(1.0f - 2.0f * t);
|
||||
float theta = PI * 2.0f * t * 3.61803398875f; // Golden ratio
|
||||
float phi = acosf(1.0f - (2.0f * t));
|
||||
float theta = PI * 2.0f * t * 3.61803398875f; // Golden ratio
|
||||
|
||||
float x_nuc = nucleus_radius_ * cosf(theta) * sinf(phi);
|
||||
float y_nuc = nucleus_radius_ * sinf(theta) * sinf(phi);
|
||||
@@ -51,16 +54,18 @@ void AtomShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Puntos restantes: distribuir en órbitas
|
||||
int orbit_points = num_points_ - nucleus_points;
|
||||
int points_per_orbit = orbit_points / num_orbits;
|
||||
if (points_per_orbit < 1) points_per_orbit = 1;
|
||||
points_per_orbit = std::max(points_per_orbit, 1);
|
||||
|
||||
int orbit_index = (index - nucleus_points) / points_per_orbit;
|
||||
if (orbit_index >= num_orbits) orbit_index = num_orbits - 1;
|
||||
if (orbit_index >= num_orbits) {
|
||||
orbit_index = num_orbits - 1;
|
||||
}
|
||||
|
||||
int point_in_orbit = (index - nucleus_points) % points_per_orbit;
|
||||
|
||||
// Ángulo del electrón en su órbita
|
||||
float electron_angle = (static_cast<float>(point_in_orbit) / static_cast<float>(points_per_orbit)) * 2.0f * PI;
|
||||
electron_angle += orbit_phase_; // Añadir rotación animada
|
||||
electron_angle += orbit_phase_; // Añadir rotación animada
|
||||
|
||||
// Inclinación del plano orbital (cada órbita en ángulo diferente)
|
||||
float orbit_tilt = (static_cast<float>(orbit_index) / static_cast<float>(num_orbits)) * PI;
|
||||
@@ -73,21 +78,21 @@ void AtomShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Inclinar el plano orbital (rotación en eje X local)
|
||||
float cos_tilt = cosf(orbit_tilt);
|
||||
float sin_tilt = sinf(orbit_tilt);
|
||||
float y_tilted = y_local * cos_tilt - z_local * sin_tilt;
|
||||
float z_tilted = y_local * sin_tilt + z_local * cos_tilt;
|
||||
float y_tilted = (y_local * cos_tilt) - (z_local * sin_tilt);
|
||||
float z_tilted = (y_local * sin_tilt) + (z_local * cos_tilt);
|
||||
|
||||
// Aplicar rotación global del átomo (eje Y)
|
||||
float cos_y = cosf(angle_y_);
|
||||
float sin_y = sinf(angle_y_);
|
||||
float x_rot = x_local * cos_y - z_tilted * sin_y;
|
||||
float z_rot = x_local * sin_y + z_tilted * cos_y;
|
||||
float x_rot = (x_local * cos_y) - (z_tilted * sin_y);
|
||||
float z_rot = (x_local * sin_y) + (z_tilted * cos_y);
|
||||
|
||||
x = x_rot;
|
||||
y = y_tilted;
|
||||
z = z_rot;
|
||||
}
|
||||
|
||||
float AtomShape::getScaleFactor(float screen_height) const {
|
||||
auto AtomShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional al radio de órbita
|
||||
// Radio órbita base = 72px (0.30 * 240px en resolución 320x240)
|
||||
const float BASE_RADIUS = 72.0f;
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
// Comportamiento: Núcleo estático + electrones orbitando en planos inclinados
|
||||
// Efecto: Modelo atómico clásico Bohr
|
||||
class AtomShape : public Shape {
|
||||
private:
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación global en eje Y (rad)
|
||||
float orbit_phase_ = 0.0f; // Fase de rotación de electrones (rad)
|
||||
float nucleus_radius_ = 0.0f; // Radio del núcleo central (píxeles)
|
||||
float orbit_radius_ = 0.0f; // Radio de las órbitas (píxeles)
|
||||
int num_points_ = 0; // Cantidad total de puntos
|
||||
private:
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación global en eje Y (rad)
|
||||
float orbit_phase_ = 0.0f; // Fase de rotación de electrones (rad)
|
||||
float nucleus_radius_ = 0.0f; // Radio del núcleo central (píxeles)
|
||||
float orbit_radius_ = 0.0f; // Radio de las órbitas (píxeles)
|
||||
int num_points_ = 0; // Cantidad total de puntos
|
||||
|
||||
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 "ATOM"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "ATOM"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "cube_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void CubeShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
size_ = screen_height * CUBE_SIZE_FACTOR;
|
||||
@@ -52,23 +55,23 @@ void CubeShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Aplicar rotación en eje Z
|
||||
float cos_z = cosf(angle_z_);
|
||||
float sin_z = sinf(angle_z_);
|
||||
float x_rot_z = x_base * cos_z - y_base * sin_z;
|
||||
float y_rot_z = x_base * sin_z + y_base * cos_z;
|
||||
float x_rot_z = (x_base * cos_z) - (y_base * sin_z);
|
||||
float y_rot_z = (x_base * sin_z) + (y_base * cos_z);
|
||||
float z_rot_z = z_base;
|
||||
|
||||
// Aplicar rotación en eje Y
|
||||
float cos_y = cosf(angle_y_);
|
||||
float sin_y = sinf(angle_y_);
|
||||
float x_rot_y = x_rot_z * cos_y + z_rot_z * sin_y;
|
||||
float x_rot_y = (x_rot_z * cos_y) + (z_rot_z * sin_y);
|
||||
float y_rot_y = y_rot_z;
|
||||
float z_rot_y = -x_rot_z * sin_y + z_rot_z * cos_y;
|
||||
float z_rot_y = (-x_rot_z * sin_y) + (z_rot_z * cos_y);
|
||||
|
||||
// Aplicar rotación en eje X
|
||||
float cos_x = cosf(angle_x_);
|
||||
float sin_x = sinf(angle_x_);
|
||||
float x_final = x_rot_y;
|
||||
float y_final = y_rot_y * cos_x - z_rot_y * sin_x;
|
||||
float z_final = y_rot_y * sin_x + z_rot_y * cos_x;
|
||||
float y_final = (y_rot_y * cos_x) - (z_rot_y * sin_x);
|
||||
float z_final = (y_rot_y * sin_x) + (z_rot_y * cos_x);
|
||||
|
||||
// Retornar coordenadas finales rotadas
|
||||
x = x_final;
|
||||
@@ -76,7 +79,7 @@ void CubeShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
z = z_final;
|
||||
}
|
||||
|
||||
float CubeShape::getScaleFactor(float screen_height) const {
|
||||
auto CubeShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional al tamaño del cubo
|
||||
// Tamaño base = 60px (resolución 320x240, factor 0.25)
|
||||
const float BASE_SIZE = 60.0f;
|
||||
@@ -105,12 +108,24 @@ void CubeShape::generateVerticesAndCenters() {
|
||||
|
||||
// 2. Añadir 6 centros de caras
|
||||
// Caras: X=±size (Y,Z varían), Y=±size (X,Z varían), Z=±size (X,Y varían)
|
||||
base_x_.push_back(size_); base_y_.push_back(0); base_z_.push_back(0); // +X
|
||||
base_x_.push_back(-size_); base_y_.push_back(0); base_z_.push_back(0); // -X
|
||||
base_x_.push_back(0); base_y_.push_back(size_); base_z_.push_back(0); // +Y
|
||||
base_x_.push_back(0); base_y_.push_back(-size_);base_z_.push_back(0); // -Y
|
||||
base_x_.push_back(0); base_y_.push_back(0); base_z_.push_back(size_); // +Z
|
||||
base_x_.push_back(0); base_y_.push_back(0); base_z_.push_back(-size_); // -Z
|
||||
base_x_.push_back(size_);
|
||||
base_y_.push_back(0);
|
||||
base_z_.push_back(0); // +X
|
||||
base_x_.push_back(-size_);
|
||||
base_y_.push_back(0);
|
||||
base_z_.push_back(0); // -X
|
||||
base_x_.push_back(0);
|
||||
base_y_.push_back(size_);
|
||||
base_z_.push_back(0); // +Y
|
||||
base_x_.push_back(0);
|
||||
base_y_.push_back(-size_);
|
||||
base_z_.push_back(0); // -Y
|
||||
base_x_.push_back(0);
|
||||
base_y_.push_back(0);
|
||||
base_z_.push_back(size_); // +Z
|
||||
base_x_.push_back(0);
|
||||
base_y_.push_back(0);
|
||||
base_z_.push_back(-size_); // -Z
|
||||
|
||||
// 3. Añadir 12 centros de aristas
|
||||
// Aristas paralelas a X (4), Y (4), Z (4)
|
||||
@@ -143,16 +158,16 @@ void CubeShape::generateVerticesAndCenters() {
|
||||
void CubeShape::generateVolumetricGrid() {
|
||||
// Calcular dimensión del grid cúbico: N³ ≈ num_points
|
||||
int grid_dim = static_cast<int>(ceilf(cbrtf(static_cast<float>(num_points_))));
|
||||
if (grid_dim < 3) grid_dim = 3; // Mínimo grid 3x3x3
|
||||
grid_dim = std::max(grid_dim, 3); // Mínimo grid 3x3x3
|
||||
|
||||
float step = (2.0f * size_) / (grid_dim - 1); // Espacio entre puntos
|
||||
|
||||
for (int ix = 0; ix < grid_dim; ix++) {
|
||||
for (int iy = 0; iy < grid_dim; iy++) {
|
||||
for (int iz = 0; iz < grid_dim; iz++) {
|
||||
float x = -size_ + ix * step;
|
||||
float y = -size_ + iy * step;
|
||||
float z = -size_ + iz * step;
|
||||
float x = -size_ + (ix * step);
|
||||
float y = -size_ + (iy * step);
|
||||
float z = -size_ + (iz * step);
|
||||
|
||||
base_x_.push_back(x);
|
||||
base_y_.push_back(y);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include <vector>
|
||||
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Cubo 3D rotante
|
||||
// Distribución:
|
||||
// - 1-8 pelotas: Solo vértices (8 puntos)
|
||||
@@ -10,28 +11,28 @@
|
||||
// - 27+ pelotas: Grid volumétrico 3D uniforme
|
||||
// Comportamiento: Rotación simultánea en ejes X, Y, Z (efecto Rubik)
|
||||
class CubeShape : public Shape {
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_z_ = 0.0f; // Ángulo de rotación en eje Z (rad)
|
||||
float size_ = 0.0f; // Mitad del lado del cubo (píxeles)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_z_ = 0.0f; // Ángulo de rotación en eje Z (rad)
|
||||
float size_ = 0.0f; // Mitad del lado del cubo (píxeles)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
|
||||
// Posiciones base 3D (sin rotar) - se calculan en generatePoints()
|
||||
std::vector<float> base_x_;
|
||||
std::vector<float> base_y_;
|
||||
std::vector<float> base_z_;
|
||||
// Posiciones base 3D (sin rotar) - se calculan en generatePoints()
|
||||
std::vector<float> base_x_;
|
||||
std::vector<float> base_y_;
|
||||
std::vector<float> base_z_;
|
||||
|
||||
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 "CUBE"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "CUBE"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
|
||||
private:
|
||||
// Métodos auxiliares para distribución de puntos
|
||||
void generateVertices(); // 8 vértices
|
||||
void generateVerticesAndCenters(); // 26 puntos (vértices + caras + aristas)
|
||||
void generateVolumetricGrid(); // Grid 3D para muchas pelotas
|
||||
private:
|
||||
// Métodos auxiliares para distribución de puntos
|
||||
void generateVertices(); // 8 vértices
|
||||
void generateVerticesAndCenters(); // 26 puntos (vértices + caras + aristas)
|
||||
void generateVolumetricGrid(); // Grid 3D para muchas pelotas
|
||||
};
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "cylinder_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib> // Para rand()
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void CylinderShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
radius_ = screen_height * CYLINDER_RADIUS_FACTOR;
|
||||
@@ -37,7 +40,7 @@ void CylinderShape::update(float delta_time, float screen_width, float screen_he
|
||||
float t = tumble_progress;
|
||||
float ease = t < 0.5f
|
||||
? 2.0f * t * t
|
||||
: 1.0f - (-2.0f * t + 2.0f) * (-2.0f * t + 2.0f) / 2.0f;
|
||||
: 1.0f - ((-2.0f * t + 2.0f) * (-2.0f * t + 2.0f) / 2.0f);
|
||||
angle_x_ = ease * tumble_target_;
|
||||
}
|
||||
} else {
|
||||
@@ -58,10 +61,10 @@ void CylinderShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Calcular número de anillos (altura) y puntos por anillo (circunferencia)
|
||||
|
||||
int num_rings = static_cast<int>(sqrtf(static_cast<float>(num_points_) * 0.5f));
|
||||
if (num_rings < 2) num_rings = 2;
|
||||
num_rings = std::max(num_rings, 2);
|
||||
|
||||
int points_per_ring = num_points_ / num_rings;
|
||||
if (points_per_ring < 3) points_per_ring = 3;
|
||||
points_per_ring = std::max(points_per_ring, 3);
|
||||
|
||||
// Obtener parámetros u (ángulo) y v (altura) del índice
|
||||
int ring = index / points_per_ring;
|
||||
@@ -80,8 +83,10 @@ void CylinderShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
float u = (static_cast<float>(point_in_ring) / static_cast<float>(points_per_ring)) * 2.0f * PI;
|
||||
|
||||
// Parámetro v (altura normalizada): [-1, 1]
|
||||
float v = (static_cast<float>(ring) / static_cast<float>(num_rings - 1)) * 2.0f - 1.0f;
|
||||
if (num_rings == 1) v = 0.0f;
|
||||
float v = ((static_cast<float>(ring) / static_cast<float>(num_rings - 1)) * 2.0f) - 1.0f;
|
||||
if (num_rings == 1) {
|
||||
v = 0.0f;
|
||||
}
|
||||
|
||||
// Ecuaciones paramétricas del cilindro
|
||||
// x = radius * cos(u)
|
||||
@@ -94,14 +99,14 @@ void CylinderShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Aplicar rotación en eje Y (principal, siempre activa)
|
||||
float cos_y = cosf(angle_y_);
|
||||
float sin_y = sinf(angle_y_);
|
||||
float x_rot_y = x_base * cos_y - z_base * sin_y;
|
||||
float z_rot_y = x_base * sin_y + z_base * cos_y;
|
||||
float x_rot_y = (x_base * cos_y) - (z_base * sin_y);
|
||||
float z_rot_y = (x_base * sin_y) + (z_base * cos_y);
|
||||
|
||||
// Aplicar rotación en eje X (tumbling ocasional)
|
||||
float cos_x = cosf(angle_x_);
|
||||
float sin_x = sinf(angle_x_);
|
||||
float y_rot = y_base * cos_x - z_rot_y * sin_x;
|
||||
float z_rot = y_base * sin_x + z_rot_y * cos_x;
|
||||
float y_rot = (y_base * cos_x) - (z_rot_y * sin_x);
|
||||
float z_rot = (y_base * sin_x) + (z_rot_y * cos_x);
|
||||
|
||||
// Retornar coordenadas finales con ambas rotaciones
|
||||
x = x_rot_y;
|
||||
@@ -109,7 +114,7 @@ void CylinderShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
z = z_rot;
|
||||
}
|
||||
|
||||
float CylinderShape::getScaleFactor(float screen_height) const {
|
||||
auto CylinderShape::getScaleFactor(float screen_height) const -> float {
|
||||
// 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;
|
||||
|
||||
@@ -6,23 +6,23 @@
|
||||
// Comportamiento: Superficie cilíndrica con rotación en eje Y + tumbling ocasional en X/Z
|
||||
// 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 angle_x_ = 0.0f; // Ángulo de rotación en eje X (tumbling ocasional)
|
||||
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
|
||||
private:
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (tumbling ocasional)
|
||||
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
|
||||
|
||||
// Sistema de tumbling ocasional
|
||||
float tumble_timer_ = 0.0f; // Temporizador para próximo tumble
|
||||
float tumble_duration_ = 0.0f; // Duración del tumble actual
|
||||
bool is_tumbling_ = false; // ¿Estamos en modo tumble?
|
||||
float tumble_target_ = 0.0f; // Ángulo objetivo del tumble
|
||||
// Sistema de tumbling ocasional
|
||||
float tumble_timer_ = 0.0f; // Temporizador para próximo tumble
|
||||
float tumble_duration_ = 0.0f; // Duración del tumble actual
|
||||
bool is_tumbling_ = false; // ¿Estamos en modo tumble?
|
||||
float tumble_target_ = 0.0f; // Ángulo objetivo del tumble
|
||||
|
||||
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;
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "helix_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void HelixShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
radius_ = screen_height * HELIX_RADIUS_FACTOR;
|
||||
@@ -41,8 +43,8 @@ void HelixShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Aplicar rotación en eje Y (horizontal)
|
||||
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;
|
||||
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
|
||||
x = x_rot;
|
||||
@@ -50,7 +52,7 @@ void HelixShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
z = z_rot;
|
||||
}
|
||||
|
||||
float HelixShape::getScaleFactor(float screen_height) const {
|
||||
auto HelixShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional a la dimensión mayor (altura total)
|
||||
// Altura base = 180px para 3 vueltas con pitch=0.25 en 240px de altura (180 = 240 * 0.25 * 3)
|
||||
const float BASE_HEIGHT = 180.0f;
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
// Comportamiento: Rotación en eje Y + animación de fase vertical
|
||||
// Ecuaciones: x = r*cos(t), y = pitch*t + phase, z = r*sin(t)
|
||||
class HelixShape : public Shape {
|
||||
private:
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float phase_offset_ = 0.0f; // Offset de fase para animación vertical (rad)
|
||||
float radius_ = 0.0f; // Radio de la espiral (píxeles)
|
||||
float pitch_ = 0.0f; // Separación vertical entre vueltas (píxeles)
|
||||
float total_height_ = 0.0f; // Altura total de la espiral (píxeles)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
private:
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float phase_offset_ = 0.0f; // Offset de fase para animación vertical (rad)
|
||||
float radius_ = 0.0f; // Radio de la espiral (píxeles)
|
||||
float pitch_ = 0.0f; // Separación vertical entre vueltas (píxeles)
|
||||
float total_height_ = 0.0f; // Altura total de la espiral (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 "HELIX"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "HELIX"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#include "icosahedron_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void IcosahedronShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
radius_ = screen_height * ICOSAHEDRON_RADIUS_FACTOR;
|
||||
@@ -21,37 +25,36 @@ void IcosahedronShape::update(float delta_time, float screen_width, float screen
|
||||
|
||||
void IcosahedronShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Proporción áurea (golden ratio)
|
||||
const float phi = (1.0f + sqrtf(5.0f)) / 2.0f;
|
||||
const float PHI = (1.0f + sqrtf(5.0f)) / 2.0f;
|
||||
|
||||
// 12 vértices del icosaedro regular normalizado
|
||||
// Basados en 3 rectángulos áureos ortogonales
|
||||
static const float vertices[12][3] = {
|
||||
const std::array<std::array<float, 3>, 12> VERTICES = {{
|
||||
// Rectángulo XY
|
||||
{-1.0f, phi, 0.0f},
|
||||
{ 1.0f, phi, 0.0f},
|
||||
{-1.0f, -phi, 0.0f},
|
||||
{ 1.0f, -phi, 0.0f},
|
||||
{-1.0f, PHI, 0.0f},
|
||||
{1.0f, PHI, 0.0f},
|
||||
{-1.0f, -PHI, 0.0f},
|
||||
{1.0f, -PHI, 0.0f},
|
||||
// Rectángulo YZ
|
||||
{ 0.0f, -1.0f, phi},
|
||||
{ 0.0f, 1.0f, phi},
|
||||
{ 0.0f, -1.0f, -phi},
|
||||
{ 0.0f, 1.0f, -phi},
|
||||
{0.0f, -1.0f, PHI},
|
||||
{0.0f, 1.0f, PHI},
|
||||
{0.0f, -1.0f, -PHI},
|
||||
{0.0f, 1.0f, -PHI},
|
||||
// Rectángulo ZX
|
||||
{ phi, 0.0f, -1.0f},
|
||||
{ phi, 0.0f, 1.0f},
|
||||
{-phi, 0.0f, -1.0f},
|
||||
{-phi, 0.0f, 1.0f}
|
||||
};
|
||||
{PHI, 0.0f, -1.0f},
|
||||
{PHI, 0.0f, 1.0f},
|
||||
{-PHI, 0.0f, -1.0f},
|
||||
{-PHI, 0.0f, 1.0f}}};
|
||||
|
||||
// Normalizar para esfera circunscrita
|
||||
const float normalization = sqrtf(1.0f + phi * phi);
|
||||
const float NORMALIZATION = sqrtf(1.0f + (PHI * PHI));
|
||||
|
||||
// Si tenemos 12 o menos puntos, usar solo vértices
|
||||
if (num_points_ <= 12) {
|
||||
int vertex_index = index % 12;
|
||||
float x_base = vertices[vertex_index][0] / normalization * radius_;
|
||||
float y_base = vertices[vertex_index][1] / normalization * radius_;
|
||||
float z_base = vertices[vertex_index][2] / normalization * radius_;
|
||||
float x_base = VERTICES[vertex_index][0] / NORMALIZATION * radius_;
|
||||
float y_base = VERTICES[vertex_index][1] / NORMALIZATION * radius_;
|
||||
float z_base = VERTICES[vertex_index][2] / NORMALIZATION * radius_;
|
||||
|
||||
// Aplicar rotaciones
|
||||
applyRotations(x_base, y_base, z_base, x, y, z);
|
||||
@@ -62,9 +65,9 @@ void IcosahedronShape::getPoint3D(int index, float& x, float& y, float& z) const
|
||||
// Distribuir puntos entre vértices (primero) y caras (después)
|
||||
if (index < 12) {
|
||||
// Primeros 12 puntos: vértices del icosaedro
|
||||
float x_base = vertices[index][0] / normalization * radius_;
|
||||
float y_base = vertices[index][1] / normalization * radius_;
|
||||
float z_base = vertices[index][2] / normalization * radius_;
|
||||
float x_base = VERTICES[index][0] / NORMALIZATION * radius_;
|
||||
float y_base = VERTICES[index][1] / NORMALIZATION * radius_;
|
||||
float z_base = VERTICES[index][2] / NORMALIZATION * radius_;
|
||||
applyRotations(x_base, y_base, z_base, x, y, z);
|
||||
return;
|
||||
}
|
||||
@@ -73,38 +76,55 @@ void IcosahedronShape::getPoint3D(int index, float& x, float& y, float& z) const
|
||||
// El icosaedro tiene 20 caras triangulares
|
||||
int remaining_points = index - 12;
|
||||
int points_per_face = (num_points_ - 12) / 20;
|
||||
if (points_per_face < 1) points_per_face = 1;
|
||||
points_per_face = std::max(points_per_face, 1);
|
||||
|
||||
int face_index = remaining_points / points_per_face;
|
||||
if (face_index >= 20) face_index = 19;
|
||||
if (face_index >= 20) {
|
||||
face_index = 19;
|
||||
}
|
||||
|
||||
int point_in_face = remaining_points % points_per_face;
|
||||
|
||||
// Definir algunas caras del icosaedro (usando índices de vértices)
|
||||
// Solo necesitamos generar puntos, no renderizar caras completas
|
||||
static const int faces[20][3] = {
|
||||
{0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
|
||||
{1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
|
||||
{3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
|
||||
{4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
|
||||
};
|
||||
static constexpr std::array<std::array<int, 3>, 20> FACES = {{
|
||||
{0, 11, 5},
|
||||
{0, 5, 1},
|
||||
{0, 1, 7},
|
||||
{0, 7, 10},
|
||||
{0, 10, 11},
|
||||
{1, 5, 9},
|
||||
{5, 11, 4},
|
||||
{11, 10, 2},
|
||||
{10, 7, 6},
|
||||
{7, 1, 8},
|
||||
{3, 9, 4},
|
||||
{3, 4, 2},
|
||||
{3, 2, 6},
|
||||
{3, 6, 8},
|
||||
{3, 8, 9},
|
||||
{4, 9, 5},
|
||||
{2, 4, 11},
|
||||
{6, 2, 10},
|
||||
{8, 6, 7},
|
||||
{9, 8, 1}}};
|
||||
|
||||
// Obtener vértices de la cara
|
||||
int v0 = faces[face_index][0];
|
||||
int v1 = faces[face_index][1];
|
||||
int v2 = faces[face_index][2];
|
||||
int v0 = FACES[face_index][0];
|
||||
int v1 = FACES[face_index][1];
|
||||
int v2 = FACES[face_index][2];
|
||||
|
||||
// Interpolar dentro del triángulo usando coordenadas baricéntricas simples
|
||||
float t = static_cast<float>(point_in_face) / static_cast<float>(points_per_face + 1);
|
||||
float u = sqrtf(t);
|
||||
float v = t - u;
|
||||
|
||||
float x_interp = vertices[v0][0] * (1.0f - u - v) + vertices[v1][0] * u + vertices[v2][0] * v;
|
||||
float y_interp = vertices[v0][1] * (1.0f - u - v) + vertices[v1][1] * u + vertices[v2][1] * v;
|
||||
float z_interp = vertices[v0][2] * (1.0f - u - v) + vertices[v1][2] * u + vertices[v2][2] * v;
|
||||
float x_interp = (VERTICES[v0][0] * (1.0f - u - v)) + (VERTICES[v1][0] * u) + (VERTICES[v2][0] * v);
|
||||
float y_interp = (VERTICES[v0][1] * (1.0f - u - v)) + (VERTICES[v1][1] * u) + (VERTICES[v2][1] * v);
|
||||
float z_interp = (VERTICES[v0][2] * (1.0f - u - v)) + (VERTICES[v1][2] * u) + (VERTICES[v2][2] * v);
|
||||
|
||||
// Proyectar a la esfera
|
||||
float len = sqrtf(x_interp * x_interp + y_interp * y_interp + z_interp * z_interp);
|
||||
float len = sqrtf((x_interp * x_interp) + (y_interp * y_interp) + (z_interp * z_interp));
|
||||
if (len > 0.0001f) {
|
||||
x_interp /= len;
|
||||
y_interp /= len;
|
||||
@@ -122,27 +142,27 @@ void IcosahedronShape::applyRotations(float x_in, float y_in, float z_in, float&
|
||||
// Aplicar rotación en eje X
|
||||
float cos_x = cosf(angle_x_);
|
||||
float sin_x = sinf(angle_x_);
|
||||
float y_rot_x = y_in * cos_x - z_in * sin_x;
|
||||
float z_rot_x = y_in * sin_x + z_in * cos_x;
|
||||
float y_rot_x = (y_in * cos_x) - (z_in * sin_x);
|
||||
float z_rot_x = (y_in * sin_x) + (z_in * cos_x);
|
||||
|
||||
// Aplicar rotación en eje Y
|
||||
float cos_y = cosf(angle_y_);
|
||||
float sin_y = sinf(angle_y_);
|
||||
float x_rot_y = x_in * cos_y - z_rot_x * sin_y;
|
||||
float z_rot_y = x_in * sin_y + z_rot_x * cos_y;
|
||||
float x_rot_y = (x_in * cos_y) - (z_rot_x * sin_y);
|
||||
float z_rot_y = (x_in * sin_y) + (z_rot_x * cos_y);
|
||||
|
||||
// Aplicar rotación en eje Z
|
||||
float cos_z = cosf(angle_z_);
|
||||
float sin_z = sinf(angle_z_);
|
||||
float x_final = x_rot_y * cos_z - y_rot_x * sin_z;
|
||||
float y_final = x_rot_y * sin_z + y_rot_x * cos_z;
|
||||
float x_final = (x_rot_y * cos_z) - (y_rot_x * sin_z);
|
||||
float y_final = (x_rot_y * sin_z) + (y_rot_x * cos_z);
|
||||
|
||||
x_out = x_final;
|
||||
y_out = y_final;
|
||||
z_out = z_rot_y;
|
||||
}
|
||||
|
||||
float IcosahedronShape::getScaleFactor(float screen_height) const {
|
||||
auto IcosahedronShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional al radio
|
||||
// Radio base = 72px (0.30 * 240px en resolución 320x240)
|
||||
const float BASE_RADIUS = 72.0f;
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
// Comportamiento: 12 vértices distribuidos uniformemente con rotación triple
|
||||
// Geometría: Basado en proporción áurea (golden ratio)
|
||||
class IcosahedronShape : public Shape {
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_z_ = 0.0f; // Ángulo de rotación en eje Z (rad)
|
||||
float radius_ = 0.0f; // Radio de la esfera circunscrita (píxeles)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_z_ = 0.0f; // Ángulo de rotación en eje Z (rad)
|
||||
float radius_ = 0.0f; // Radio de la esfera circunscrita (píxeles)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
|
||||
// Helper para aplicar rotaciones triple XYZ
|
||||
void applyRotations(float x_in, float y_in, float z_in, float& x_out, float& y_out, float& z_out) const;
|
||||
// Helper para aplicar rotaciones triple XYZ
|
||||
void applyRotations(float x_in, float y_in, float z_in, float& x_out, float& y_out, float& z_out) const;
|
||||
|
||||
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 "ICOSAHEDRON"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "ICOSAHEDRON"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "lissajous_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void LissajousShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
amplitude_ = screen_height * LISSAJOUS_SIZE_FACTOR;
|
||||
@@ -33,21 +35,21 @@ void LissajousShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// x(t) = A * sin(freq_x * t + phase_x)
|
||||
// y(t) = A * sin(freq_y * t)
|
||||
// z(t) = A * sin(freq_z * t + phase_z)
|
||||
float x_local = amplitude_ * sinf(freq_x_ * t + phase_x_);
|
||||
float x_local = amplitude_ * sinf((freq_x_ * t) + phase_x_);
|
||||
float y_local = amplitude_ * sinf(freq_y_ * t);
|
||||
float z_local = amplitude_ * sinf(freq_z_ * t + phase_z_);
|
||||
float z_local = amplitude_ * sinf((freq_z_ * t) + phase_z_);
|
||||
|
||||
// Aplicar rotación global en eje X
|
||||
float cos_x = cosf(rotation_x_);
|
||||
float sin_x = sinf(rotation_x_);
|
||||
float y_rot = y_local * cos_x - z_local * sin_x;
|
||||
float z_rot = y_local * sin_x + z_local * cos_x;
|
||||
float y_rot = (y_local * cos_x) - (z_local * sin_x);
|
||||
float z_rot = (y_local * sin_x) + (z_local * cos_x);
|
||||
|
||||
// Aplicar rotación global en eje Y
|
||||
float cos_y = cosf(rotation_y_);
|
||||
float sin_y = sinf(rotation_y_);
|
||||
float x_final = x_local * cos_y - z_rot * sin_y;
|
||||
float z_final = x_local * sin_y + z_rot * cos_y;
|
||||
float x_final = (x_local * cos_y) - (z_rot * sin_y);
|
||||
float z_final = (x_local * sin_y) + (z_rot * cos_y);
|
||||
|
||||
// Retornar coordenadas rotadas
|
||||
x = x_final;
|
||||
@@ -55,7 +57,7 @@ void LissajousShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
z = z_final;
|
||||
}
|
||||
|
||||
float LissajousShape::getScaleFactor(float screen_height) const {
|
||||
auto LissajousShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional a la amplitud de la curva
|
||||
// Amplitud base = 84px (0.35 * 240px en resolución 320x240)
|
||||
const float BASE_SIZE = 84.0f;
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
// Comportamiento: Curva paramétrica 3D con rotación global y animación de fase
|
||||
// Ecuaciones: x(t) = A*sin(freq_x*t + phase_x), y(t) = A*sin(freq_y*t), z(t) = A*sin(freq_z*t + phase_z)
|
||||
class LissajousShape : public Shape {
|
||||
private:
|
||||
float freq_x_ = 0.0f; // Frecuencia en eje X
|
||||
float freq_y_ = 0.0f; // Frecuencia en eje Y
|
||||
float freq_z_ = 0.0f; // Frecuencia en eje Z
|
||||
float phase_x_ = 0.0f; // Desfase X (animado)
|
||||
float phase_z_ = 0.0f; // Desfase Z (animado)
|
||||
float rotation_x_ = 0.0f; // Rotación global en eje X (rad)
|
||||
float rotation_y_ = 0.0f; // Rotación global en eje Y (rad)
|
||||
float amplitude_ = 0.0f; // Amplitud de la curva (píxeles)
|
||||
int num_points_ = 0; // Cantidad total de puntos
|
||||
private:
|
||||
float freq_x_ = 0.0f; // Frecuencia en eje X
|
||||
float freq_y_ = 0.0f; // Frecuencia en eje Y
|
||||
float freq_z_ = 0.0f; // Frecuencia en eje Z
|
||||
float phase_x_ = 0.0f; // Desfase X (animado)
|
||||
float phase_z_ = 0.0f; // Desfase Z (animado)
|
||||
float rotation_x_ = 0.0f; // Rotación global en eje X (rad)
|
||||
float rotation_y_ = 0.0f; // Rotación global en eje Y (rad)
|
||||
float amplitude_ = 0.0f; // Amplitud de la curva (píxeles)
|
||||
int num_points_ = 0; // Cantidad total de puntos
|
||||
|
||||
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 "LISSAJOUS"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "LISSAJOUS"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
};
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#include "png_shape.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "external/stb_image.h"
|
||||
#include "resource_manager.hpp"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
PNGShape::PNGShape(const char* png_path) {
|
||||
// Cargar PNG desde path
|
||||
if (!loadPNG(png_path)) {
|
||||
std::cerr << "[PNGShape] Usando fallback 10x10" << std::endl;
|
||||
std::cerr << "[PNGShape] Usando fallback 10x10" << '\n';
|
||||
// Fallback: generar un cuadrado simple si falla la carga
|
||||
image_width_ = 10;
|
||||
image_height_ = 10;
|
||||
@@ -21,7 +23,7 @@ PNGShape::PNGShape(const char* png_path) {
|
||||
next_idle_time_ = PNG_IDLE_TIME_MIN + (rand() % 1000) / 1000.0f * (PNG_IDLE_TIME_MAX - PNG_IDLE_TIME_MIN);
|
||||
}
|
||||
|
||||
bool PNGShape::loadPNG(const char* resource_key) {
|
||||
auto PNGShape::loadPNG(const char* resource_key) -> bool {
|
||||
{
|
||||
std::string fn = std::string(resource_key);
|
||||
fn = fn.substr(fn.find_last_of("\\/") + 1);
|
||||
@@ -30,15 +32,16 @@ bool PNGShape::loadPNG(const char* resource_key) {
|
||||
unsigned char* file_data = nullptr;
|
||||
size_t file_size = 0;
|
||||
if (!ResourceManager::loadResource(resource_key, file_data, file_size)) {
|
||||
std::cerr << "[PNGShape] ERROR: recurso no encontrado: " << resource_key << std::endl;
|
||||
std::cerr << "[PNGShape] ERROR: recurso no encontrado: " << resource_key << '\n';
|
||||
return false;
|
||||
}
|
||||
int width, height, channels;
|
||||
unsigned char* pixels = stbi_load_from_memory(file_data, static_cast<int>(file_size),
|
||||
&width, &height, &channels, 1);
|
||||
int width;
|
||||
int height;
|
||||
int channels;
|
||||
unsigned char* pixels = stbi_load_from_memory(file_data, static_cast<int>(file_size), &width, &height, &channels, 1);
|
||||
delete[] file_data;
|
||||
if (!pixels) {
|
||||
std::cerr << "[PNGShape] ERROR al decodificar PNG: " << stbi_failure_reason() << std::endl;
|
||||
if (pixels == nullptr) {
|
||||
std::cerr << "[PNGShape] ERROR al decodificar PNG: " << stbi_failure_reason() << '\n';
|
||||
return false;
|
||||
}
|
||||
image_width_ = width;
|
||||
@@ -57,9 +60,11 @@ void PNGShape::detectEdges() {
|
||||
// Detectar píxeles del contorno (píxeles blancos con al menos un vecino negro)
|
||||
for (int y = 0; y < image_height_; y++) {
|
||||
for (int x = 0; x < image_width_; x++) {
|
||||
int idx = y * image_width_ + x;
|
||||
int idx = (y * image_width_) + x;
|
||||
|
||||
if (!pixel_data_[idx]) continue; // Solo píxeles blancos
|
||||
if (!pixel_data_[idx]) {
|
||||
continue; // Solo píxeles blancos
|
||||
}
|
||||
|
||||
// Verificar vecinos (arriba, abajo, izq, der)
|
||||
bool is_edge = false;
|
||||
@@ -68,10 +73,10 @@ void PNGShape::detectEdges() {
|
||||
is_edge = true; // Bordes de la imagen
|
||||
} else {
|
||||
// Verificar 4 vecinos
|
||||
if (!pixel_data_[idx - 1] || // Izquierda
|
||||
!pixel_data_[idx + 1] || // Derecha
|
||||
!pixel_data_[idx - image_width_] || // Arriba
|
||||
!pixel_data_[idx + image_width_]) { // Abajo
|
||||
if (!pixel_data_[idx - 1] || // Izquierda
|
||||
!pixel_data_[idx + 1] || // Derecha
|
||||
!pixel_data_[idx - image_width_] || // Arriba
|
||||
!pixel_data_[idx + image_width_]) { // Abajo
|
||||
is_edge = true;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +95,7 @@ void PNGShape::floodFill() {
|
||||
|
||||
for (int y = 0; y < image_height_; y++) {
|
||||
for (int x = 0; x < image_width_; x++) {
|
||||
int idx = y * image_width_ + x;
|
||||
int idx = (y * image_width_) + x;
|
||||
if (pixel_data_[idx]) {
|
||||
filled_points_.push_back({static_cast<float>(x), static_cast<float>(y)});
|
||||
}
|
||||
@@ -114,8 +119,8 @@ void PNGShape::generatePoints(int num_points, float screen_width, float screen_h
|
||||
num_layers_ = PNG_NUM_EXTRUSION_LAYERS;
|
||||
|
||||
// Generar AMBOS conjuntos de puntos (relleno Y bordes)
|
||||
floodFill(); // Generar filled_points_
|
||||
detectEdges(); // Generar edge_points_
|
||||
floodFill(); // Generar filled_points_
|
||||
detectEdges(); // Generar edge_points_
|
||||
|
||||
// Guardar copias originales (las funciones de filtrado modifican los vectores)
|
||||
std::vector<Point2D> filled_points_original = filled_points_;
|
||||
@@ -123,7 +128,7 @@ void PNGShape::generatePoints(int num_points, float screen_width, float screen_h
|
||||
|
||||
// Conjunto de puntos ACTIVO (será modificado por filtros)
|
||||
std::vector<Point2D> active_points_data;
|
||||
std::string mode_name = "";
|
||||
std::string mode_name;
|
||||
|
||||
// === SISTEMA DE DISTRIBUCIÓN ADAPTATIVA ===
|
||||
// Estrategia: Optimizar según número de pelotas disponibles
|
||||
@@ -196,8 +201,6 @@ void PNGShape::generatePoints(int num_points, float screen_width, float screen_h
|
||||
std::vector<Point2D> vertices = extractCornerVertices(source_for_vertices);
|
||||
if (!vertices.empty() && vertices.size() < active_points_data.size()) {
|
||||
active_points_data = vertices;
|
||||
num_2d_points = active_points_data.size();
|
||||
total_3d_points = num_2d_points * num_layers_;
|
||||
mode_name = "VÉRTICES";
|
||||
}
|
||||
}
|
||||
@@ -216,7 +219,7 @@ void PNGShape::generatePoints(int num_points, float screen_width, float screen_h
|
||||
|
||||
// Extraer filas alternas de puntos (FUNCIÓN PURA: no modifica parámetros)
|
||||
// Recibe vector original y devuelve nuevo vector filtrado
|
||||
std::vector<PNGShape::Point2D> PNGShape::extractAlternateRows(const std::vector<Point2D>& source, int row_skip) {
|
||||
auto PNGShape::extractAlternateRows(const std::vector<Point2D>& source, int row_skip) -> std::vector<PNGShape::Point2D> {
|
||||
std::vector<Point2D> result;
|
||||
|
||||
if (row_skip <= 1 || source.empty()) {
|
||||
@@ -243,7 +246,7 @@ std::vector<PNGShape::Point2D> PNGShape::extractAlternateRows(const std::vector<
|
||||
}
|
||||
|
||||
// Extraer vértices y esquinas (FUNCIÓN PURA: devuelve nuevo vector)
|
||||
std::vector<PNGShape::Point2D> PNGShape::extractCornerVertices(const std::vector<Point2D>& source) {
|
||||
auto PNGShape::extractCornerVertices(const std::vector<Point2D>& source) -> std::vector<PNGShape::Point2D> {
|
||||
std::vector<Point2D> result;
|
||||
|
||||
if (source.empty()) {
|
||||
@@ -267,9 +270,9 @@ std::vector<PNGShape::Point2D> PNGShape::extractCornerVertices(const std::vector
|
||||
|
||||
// Generar puntos en extremos de cada fila
|
||||
for (const auto& [row_y, extremes] : row_extremes) {
|
||||
result.push_back({extremes.first, static_cast<float>(row_y)}); // Extremo izquierdo
|
||||
if (extremes.second != extremes.first) { // Solo añadir derecho si es diferente
|
||||
result.push_back({extremes.second, static_cast<float>(row_y)}); // Extremo derecho
|
||||
result.push_back({extremes.first, static_cast<float>(row_y)}); // Extremo izquierdo
|
||||
if (extremes.second != extremes.first) { // Solo añadir derecho si es diferente
|
||||
result.push_back({extremes.second, static_cast<float>(row_y)}); // Extremo derecho
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,8 +379,8 @@ void PNGShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
float v = y_base / (logo_size * 0.5f);
|
||||
|
||||
// Calcular pivoteo (amplitudes más grandes)
|
||||
float tilt_amount_x = sinf(tilt_x_) * 0.15f; // 15%
|
||||
float tilt_amount_y = sinf(tilt_y_) * 0.1f; // 10%
|
||||
float tilt_amount_x = sinf(tilt_x_) * 0.15f; // 15%
|
||||
float tilt_amount_y = sinf(tilt_y_) * 0.1f; // 10%
|
||||
|
||||
// Aplicar pivoteo proporcional al tamaño del logo
|
||||
float z_tilt = (u * tilt_amount_y + v * tilt_amount_x) * logo_size;
|
||||
@@ -386,14 +389,14 @@ void PNGShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Aplicar rotación en eje Y (horizontal)
|
||||
float cos_y = cosf(angle_y_);
|
||||
float sin_y = sinf(angle_y_);
|
||||
float x_rot_y = x_base * cos_y - z_base * sin_y;
|
||||
float z_rot_y = x_base * sin_y + z_base * cos_y;
|
||||
float x_rot_y = (x_base * cos_y) - (z_base * sin_y);
|
||||
float z_rot_y = (x_base * sin_y) + (z_base * cos_y);
|
||||
|
||||
// Aplicar rotación en eje X (vertical)
|
||||
float cos_x = cosf(angle_x_);
|
||||
float sin_x = sinf(angle_x_);
|
||||
float y_rot = y_base * cos_x - z_rot_y * sin_x;
|
||||
float z_rot = y_base * sin_x + z_rot_y * cos_x;
|
||||
float y_rot = (y_base * cos_x) - (z_rot_y * sin_x);
|
||||
float z_rot = (y_base * sin_x) + (z_rot_y * cos_x);
|
||||
|
||||
// Retornar coordenadas finales
|
||||
x = x_rot_y;
|
||||
@@ -408,7 +411,7 @@ void PNGShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
}
|
||||
}
|
||||
|
||||
float PNGShape::getScaleFactor(float screen_height) const {
|
||||
auto PNGShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Escala dinámica según resolución
|
||||
return PNG_SIZE_FACTOR;
|
||||
}
|
||||
@@ -432,7 +435,7 @@ void PNGShape::setConvergence(float convergence) {
|
||||
}
|
||||
|
||||
// Obtener progreso del flip actual (0.0 = inicio del flip, 1.0 = fin del flip)
|
||||
float PNGShape::getFlipProgress() const {
|
||||
auto PNGShape::getFlipProgress() const -> float {
|
||||
if (!is_flipping_) {
|
||||
return 0.0f; // No está flipping, progreso = 0
|
||||
}
|
||||
|
||||
@@ -1,104 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "shape.hpp"
|
||||
#include "defines.hpp" // Para PNG_IDLE_TIME_MIN/MAX constantes
|
||||
#include <cstdlib> // Para rand()
|
||||
#include <vector>
|
||||
#include <cstdlib> // Para rand()
|
||||
|
||||
#include "defines.hpp" // Para PNG_IDLE_TIME_MIN/MAX constantes
|
||||
#include "shape.hpp"
|
||||
|
||||
// Figura: Shape generada desde PNG 1-bit (blanco sobre negro)
|
||||
// Enfoque A: Extrusión 2D (implementado)
|
||||
// Enfoque B: Voxelización 3D (preparado para futuro)
|
||||
class PNGShape : public Shape {
|
||||
private:
|
||||
// Datos de la imagen cargada
|
||||
int image_width_ = 0;
|
||||
int image_height_ = 0;
|
||||
std::vector<bool> pixel_data_; // Mapa de píxeles blancos (true = blanco)
|
||||
private:
|
||||
// Datos de la imagen cargada
|
||||
int image_width_ = 0;
|
||||
int image_height_ = 0;
|
||||
std::vector<bool> pixel_data_; // Mapa de píxeles blancos (true = blanco)
|
||||
|
||||
// Puntos generados (Enfoque A: Extrusión 2D)
|
||||
struct Point2D {
|
||||
float x, y;
|
||||
};
|
||||
std::vector<Point2D> edge_points_; // Contorno (solo bordes) - ORIGINAL sin optimizar
|
||||
std::vector<Point2D> filled_points_; // Relleno completo - ORIGINAL sin optimizar
|
||||
std::vector<Point2D> optimized_points_; // Puntos finales optimizados (usado por getPoint3D)
|
||||
// Puntos generados (Enfoque A: Extrusión 2D)
|
||||
struct Point2D {
|
||||
float x, y;
|
||||
};
|
||||
std::vector<Point2D> edge_points_; // Contorno (solo bordes) - ORIGINAL sin optimizar
|
||||
std::vector<Point2D> filled_points_; // Relleno completo - ORIGINAL sin optimizar
|
||||
std::vector<Point2D> optimized_points_; // Puntos finales optimizados (usado por getPoint3D)
|
||||
|
||||
// Parámetros de extrusión
|
||||
float extrusion_depth_ = 0.0f; // Profundidad de extrusión en Z
|
||||
int num_layers_ = 0; // Capas de extrusión (más capas = más denso)
|
||||
// Parámetros de extrusión
|
||||
float extrusion_depth_ = 0.0f; // Profundidad de extrusión en Z
|
||||
int num_layers_ = 0; // Capas de extrusión (más capas = más denso)
|
||||
|
||||
// Rotación "legible" (de frente con volteretas ocasionales)
|
||||
float angle_x_ = 0.0f;
|
||||
float angle_y_ = 0.0f;
|
||||
float idle_timer_ = 0.0f; // Timer para tiempo de frente
|
||||
float flip_timer_ = 0.0f; // Timer para voltereta
|
||||
float next_idle_time_ = 5.0f; // Próximo tiempo de espera (aleatorio)
|
||||
bool is_flipping_ = false; // Estado: quieto o voltereta
|
||||
int flip_axis_ = 0; // Eje de voltereta (0=X, 1=Y, 2=ambos)
|
||||
// Rotación "legible" (de frente con volteretas ocasionales)
|
||||
float angle_x_ = 0.0f;
|
||||
float angle_y_ = 0.0f;
|
||||
float idle_timer_ = 0.0f; // Timer para tiempo de frente
|
||||
float flip_timer_ = 0.0f; // Timer para voltereta
|
||||
float next_idle_time_ = 5.0f; // Próximo tiempo de espera (aleatorio)
|
||||
bool is_flipping_ = false; // Estado: quieto o voltereta
|
||||
int flip_axis_ = 0; // Eje de voltereta (0=X, 1=Y, 2=ambos)
|
||||
|
||||
// Pivoteo sutil en estado IDLE
|
||||
float tilt_x_ = 0.0f; // Oscilación sutil en eje X
|
||||
float tilt_y_ = 0.0f; // Oscilación sutil en eje Y
|
||||
// Pivoteo sutil en estado IDLE
|
||||
float tilt_x_ = 0.0f; // Oscilación sutil en eje X
|
||||
float tilt_y_ = 0.0f; // Oscilación sutil en eje Y
|
||||
|
||||
// Modo LOGO (intervalos de flip más largos)
|
||||
bool is_logo_mode_ = false; // true = usar intervalos LOGO (más lentos)
|
||||
// Modo LOGO (intervalos de flip más largos)
|
||||
bool is_logo_mode_ = false; // true = usar intervalos LOGO (más lentos)
|
||||
|
||||
// Sistema de convergencia (solo relevante en modo LOGO)
|
||||
float current_convergence_ = 0.0f; // Porcentaje actual de convergencia (0.0-1.0)
|
||||
bool convergence_threshold_reached_ = false; // true si ha alcanzado umbral mínimo (80%)
|
||||
// Sistema de convergencia (solo relevante en modo LOGO)
|
||||
float current_convergence_ = 0.0f; // Porcentaje actual de convergencia (0.0-1.0)
|
||||
bool convergence_threshold_reached_ = false; // true si ha alcanzado umbral mínimo (80%)
|
||||
|
||||
// Sistema de tracking de flips (para modo LOGO - espera de flips)
|
||||
int flip_count_ = 0; // Contador de flips completados (reset al entrar a LOGO)
|
||||
bool was_flipping_last_frame_ = false; // Estado previo para detectar transiciones
|
||||
// Sistema de tracking de flips (para modo LOGO - espera de flips)
|
||||
int flip_count_ = 0; // Contador de flips completados (reset al entrar a LOGO)
|
||||
bool was_flipping_last_frame_ = false; // Estado previo para detectar transiciones
|
||||
|
||||
// Dimensiones normalizadas
|
||||
float scale_factor_ = 1.0f;
|
||||
float center_offset_x_ = 0.0f;
|
||||
float center_offset_y_ = 0.0f;
|
||||
// Dimensiones normalizadas
|
||||
float scale_factor_ = 1.0f;
|
||||
float center_offset_x_ = 0.0f;
|
||||
float center_offset_y_ = 0.0f;
|
||||
|
||||
int num_points_ = 0; // Total de puntos generados (para indexación)
|
||||
int num_points_ = 0; // Total de puntos generados (para indexación)
|
||||
|
||||
// Métodos internos
|
||||
bool loadPNG(const char* path); // Cargar PNG con stb_image
|
||||
void detectEdges(); // Detectar contorno (Enfoque A)
|
||||
void floodFill(); // Rellenar interior (Enfoque B - futuro)
|
||||
void generateExtrudedPoints(); // Generar puntos con extrusión 2D
|
||||
// Métodos internos
|
||||
bool loadPNG(const char* resource_key); // Cargar PNG con stb_image
|
||||
void detectEdges(); // Detectar contorno (Enfoque A)
|
||||
void floodFill(); // Rellenar interior (Enfoque B - futuro)
|
||||
void generateExtrudedPoints(); // Generar puntos con extrusión 2D
|
||||
|
||||
// Métodos de distribución adaptativa (funciones puras, no modifican parámetros)
|
||||
std::vector<Point2D> extractAlternateRows(const std::vector<Point2D>& source, int row_skip); // Extraer filas alternas
|
||||
std::vector<Point2D> extractCornerVertices(const std::vector<Point2D>& source); // Extraer vértices/esquinas
|
||||
// Métodos de distribución adaptativa (funciones puras, no modifican parámetros)
|
||||
static std::vector<Point2D> extractAlternateRows(const std::vector<Point2D>& source, int row_skip); // Extraer filas alternas
|
||||
static std::vector<Point2D> extractCornerVertices(const std::vector<Point2D>& source); // Extraer vértices/esquinas
|
||||
|
||||
public:
|
||||
// Constructor: recibe path relativo al PNG
|
||||
PNGShape(const char* png_path = "data/shapes/jailgames.png");
|
||||
public:
|
||||
// Constructor: recibe path relativo al PNG
|
||||
PNGShape(const char* png_path = "data/shapes/jailgames.png");
|
||||
|
||||
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 "PNG SHAPE"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "PNG SHAPE"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
|
||||
// Consultar estado de flip
|
||||
bool isFlipping() const { return is_flipping_; }
|
||||
// Consultar estado de flip
|
||||
bool isFlipping() const { return is_flipping_; }
|
||||
|
||||
// Obtener progreso del flip actual (0.0 = inicio, 1.0 = fin)
|
||||
float getFlipProgress() const;
|
||||
// Obtener progreso del flip actual (0.0 = inicio, 1.0 = fin)
|
||||
float getFlipProgress() const;
|
||||
|
||||
// Obtener número de flips completados (para modo LOGO)
|
||||
int getFlipCount() const { return flip_count_; }
|
||||
// Obtener número de flips completados (para modo LOGO)
|
||||
int getFlipCount() const { return flip_count_; }
|
||||
|
||||
// Resetear contador de flips (llamar al entrar a LOGO MODE)
|
||||
void resetFlipCount() { flip_count_ = 0; was_flipping_last_frame_ = false; }
|
||||
// Resetear contador de flips (llamar al entrar a LOGO MODE)
|
||||
void resetFlipCount() {
|
||||
flip_count_ = 0;
|
||||
was_flipping_last_frame_ = false;
|
||||
}
|
||||
|
||||
// Control de modo LOGO (flip intervals más largos)
|
||||
void setLogoMode(bool enable) {
|
||||
is_logo_mode_ = enable;
|
||||
// Recalcular next_idle_time_ con el rango apropiado
|
||||
float idle_min = enable ? PNG_IDLE_TIME_MIN_LOGO : PNG_IDLE_TIME_MIN;
|
||||
float idle_max = enable ? PNG_IDLE_TIME_MAX_LOGO : PNG_IDLE_TIME_MAX;
|
||||
next_idle_time_ = idle_min + (rand() % 1000) / 1000.0f * (idle_max - idle_min);
|
||||
}
|
||||
// Control de modo LOGO (flip intervals más largos)
|
||||
void setLogoMode(bool enable) {
|
||||
is_logo_mode_ = enable;
|
||||
// Recalcular next_idle_time_ con el rango apropiado
|
||||
float idle_min = enable ? PNG_IDLE_TIME_MIN_LOGO : PNG_IDLE_TIME_MIN;
|
||||
float idle_max = enable ? PNG_IDLE_TIME_MAX_LOGO : PNG_IDLE_TIME_MAX;
|
||||
next_idle_time_ = idle_min + (rand() % 1000) / 1000.0f * (idle_max - idle_min);
|
||||
}
|
||||
|
||||
// Sistema de convergencia (override de Shape::setConvergence)
|
||||
void setConvergence(float convergence) override;
|
||||
// Sistema de convergencia (override de Shape::setConvergence)
|
||||
void setConvergence(float convergence) override;
|
||||
};
|
||||
|
||||
@@ -2,34 +2,34 @@
|
||||
|
||||
// Interfaz abstracta para todas las figuras 3D
|
||||
class Shape {
|
||||
public:
|
||||
virtual ~Shape() = default;
|
||||
public:
|
||||
virtual ~Shape() = default;
|
||||
|
||||
// Generar distribución inicial de puntos en la figura
|
||||
// num_points: cantidad de pelotas a distribuir
|
||||
// screen_width/height: dimensiones del área de juego (para escalar)
|
||||
virtual void generatePoints(int num_points, float screen_width, float screen_height) = 0;
|
||||
// Generar distribución inicial de puntos en la figura
|
||||
// num_points: cantidad de pelotas a distribuir
|
||||
// screen_width/height: dimensiones del área de juego (para escalar)
|
||||
virtual void generatePoints(int num_points, float screen_width, float screen_height) = 0;
|
||||
|
||||
// Actualizar animación de la figura (rotación, deformación, etc.)
|
||||
// delta_time: tiempo transcurrido desde último frame
|
||||
// screen_width/height: dimensiones actuales (puede cambiar con F4)
|
||||
virtual void update(float delta_time, float screen_width, float screen_height) = 0;
|
||||
// Actualizar animación de la figura (rotación, deformación, etc.)
|
||||
// delta_time: tiempo transcurrido desde último frame
|
||||
// screen_width/height: dimensiones actuales (puede cambiar con F4)
|
||||
virtual void update(float delta_time, float screen_width, float screen_height) = 0;
|
||||
|
||||
// Obtener posición 3D del punto i después de transformaciones (rotación, etc.)
|
||||
// index: índice del punto (0 a num_points-1)
|
||||
// x, y, z: coordenadas 3D en espacio mundo (centradas en 0,0,0)
|
||||
virtual void getPoint3D(int index, float& x, float& y, float& z) const = 0;
|
||||
// Obtener posición 3D del punto i después de transformaciones (rotación, etc.)
|
||||
// index: índice del punto (0 a num_points-1)
|
||||
// x, y, z: coordenadas 3D en espacio mundo (centradas en 0,0,0)
|
||||
virtual void getPoint3D(int index, float& x, float& y, float& z) const = 0;
|
||||
|
||||
// Obtener nombre de la figura para debug display
|
||||
virtual const char* getName() const = 0;
|
||||
// Obtener nombre de la figura para debug display
|
||||
virtual const char* getName() const = 0;
|
||||
|
||||
// Obtener factor de escala para ajustar física según tamaño de figura
|
||||
// screen_height: altura actual de pantalla
|
||||
// Retorna: factor multiplicador para constantes de física (spring_k, damping, etc.)
|
||||
virtual float getScaleFactor(float screen_height) const = 0;
|
||||
// Obtener factor de escala para ajustar física según tamaño de figura
|
||||
// screen_height: altura actual de pantalla
|
||||
// Retorna: factor multiplicador para constantes de física (spring_k, damping, etc.)
|
||||
virtual float getScaleFactor(float screen_height) const = 0;
|
||||
|
||||
// Notificar a la figura sobre el porcentaje de convergencia (pelotas cerca del objetivo)
|
||||
// convergence: valor de 0.0 (0%) a 1.0 (100%) indicando cuántas pelotas están en posición
|
||||
// Default: no-op (la mayoría de figuras no necesitan esta información)
|
||||
virtual void setConvergence(float convergence) {}
|
||||
// Notificar a la figura sobre el porcentaje de convergencia (pelotas cerca del objetivo)
|
||||
// convergence: valor de 0.0 (0%) a 1.0 (100%) indicando cuántas pelotas están en posición
|
||||
// Default: no-op (la mayoría de figuras no necesitan esta información)
|
||||
virtual void setConvergence(float convergence) {}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "sphere_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void SphereShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
radius_ = screen_height * ROTOBALL_RADIUS_FACTOR;
|
||||
@@ -19,12 +21,12 @@ void SphereShape::update(float delta_time, float screen_width, float screen_heig
|
||||
|
||||
void SphereShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Algoritmo Fibonacci Sphere para distribución uniforme
|
||||
const float golden_ratio = (1.0f + sqrtf(5.0f)) / 2.0f;
|
||||
const float angle_increment = PI * 2.0f * golden_ratio;
|
||||
const float GOLDEN_RATIO = (1.0f + sqrtf(5.0f)) / 2.0f;
|
||||
const float ANGLE_INCREMENT = PI * 2.0f * GOLDEN_RATIO;
|
||||
|
||||
float t = static_cast<float>(index) / static_cast<float>(num_points_);
|
||||
float phi = acosf(1.0f - 2.0f * t); // Latitud
|
||||
float theta = angle_increment * static_cast<float>(index); // Longitud
|
||||
float phi = acosf(1.0f - (2.0f * t)); // Latitud
|
||||
float theta = ANGLE_INCREMENT * static_cast<float>(index); // Longitud
|
||||
|
||||
// Convertir coordenadas esféricas a cartesianas
|
||||
float x_base = cosf(theta) * sinf(phi) * radius_;
|
||||
@@ -34,14 +36,14 @@ void SphereShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// 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;
|
||||
float x_rot = (x_base * cos_y) - (z_base * sin_y);
|
||||
float z_rot = (x_base * sin_y) + (z_base * cos_y);
|
||||
|
||||
// Aplicar rotación en eje X
|
||||
float cos_x = cosf(angle_x_);
|
||||
float sin_x = sinf(angle_x_);
|
||||
float y_rot = y_base * cos_x - z_rot * sin_x;
|
||||
float z_final = y_base * sin_x + z_rot * cos_x;
|
||||
float y_rot = (y_base * cos_x) - (z_rot * sin_x);
|
||||
float z_final = (y_base * sin_x) + (z_rot * cos_x);
|
||||
|
||||
// Retornar coordenadas finales rotadas
|
||||
x = x_rot;
|
||||
@@ -49,7 +51,7 @@ void SphereShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
z = z_final;
|
||||
}
|
||||
|
||||
float SphereShape::getScaleFactor(float screen_height) const {
|
||||
auto SphereShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional al radio
|
||||
// Radio base = 80px (resolución 320x240)
|
||||
const float BASE_RADIUS = 80.0f;
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
// Comportamiento: Rotación dual en ejes X e Y
|
||||
// Uso anterior: RotoBall
|
||||
class SphereShape : public Shape {
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float radius_ = 0.0f; // Radio de la esfera (píxeles)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float radius_ = 0.0f; // Radio de la esfera (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 "SPHERE"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "SPHERE"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "torus_shape.hpp"
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
void TorusShape::generatePoints(int num_points, float screen_width, float screen_height) {
|
||||
num_points_ = num_points;
|
||||
major_radius_ = screen_height * TORUS_MAJOR_RADIUS_FACTOR;
|
||||
@@ -26,10 +29,10 @@ void TorusShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
|
||||
// Calcular número aproximado de anillos y puntos por anillo
|
||||
int num_rings = static_cast<int>(sqrtf(static_cast<float>(num_points_) * 0.5f));
|
||||
if (num_rings < 2) num_rings = 2;
|
||||
num_rings = std::max(num_rings, 2);
|
||||
|
||||
int points_per_ring = num_points_ / num_rings;
|
||||
if (points_per_ring < 3) points_per_ring = 3;
|
||||
points_per_ring = std::max(points_per_ring, 3);
|
||||
|
||||
// Obtener parámetros u y v del índice
|
||||
int ring = index / points_per_ring;
|
||||
@@ -57,7 +60,7 @@ void TorusShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
float cos_u = cosf(u);
|
||||
float sin_u = sinf(u);
|
||||
|
||||
float radius_at_v = major_radius_ + minor_radius_ * cos_v;
|
||||
float radius_at_v = major_radius_ + (minor_radius_ * cos_v);
|
||||
|
||||
float x_base = radius_at_v * cos_u;
|
||||
float y_base = radius_at_v * sin_u;
|
||||
@@ -66,20 +69,20 @@ void TorusShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
// Aplicar rotación en eje X
|
||||
float cos_x = cosf(angle_x_);
|
||||
float sin_x = sinf(angle_x_);
|
||||
float y_rot_x = y_base * cos_x - z_base * sin_x;
|
||||
float z_rot_x = y_base * sin_x + z_base * cos_x;
|
||||
float y_rot_x = (y_base * cos_x) - (z_base * sin_x);
|
||||
float z_rot_x = (y_base * sin_x) + (z_base * cos_x);
|
||||
|
||||
// Aplicar rotación en eje Y
|
||||
float cos_y = cosf(angle_y_);
|
||||
float sin_y = sinf(angle_y_);
|
||||
float x_rot_y = x_base * cos_y - z_rot_x * sin_y;
|
||||
float z_rot_y = x_base * sin_y + z_rot_x * cos_y;
|
||||
float x_rot_y = (x_base * cos_y) - (z_rot_x * sin_y);
|
||||
float z_rot_y = (x_base * sin_y) + (z_rot_x * cos_y);
|
||||
|
||||
// Aplicar rotación en eje Z
|
||||
float cos_z = cosf(angle_z_);
|
||||
float sin_z = sinf(angle_z_);
|
||||
float x_final = x_rot_y * cos_z - y_rot_x * sin_z;
|
||||
float y_final = x_rot_y * sin_z + y_rot_x * cos_z;
|
||||
float x_final = (x_rot_y * cos_z) - (y_rot_x * sin_z);
|
||||
float y_final = (x_rot_y * sin_z) + (y_rot_x * cos_z);
|
||||
|
||||
// Retornar coordenadas finales rotadas
|
||||
x = x_final;
|
||||
@@ -87,7 +90,7 @@ void TorusShape::getPoint3D(int index, float& x, float& y, float& z) const {
|
||||
z = z_rot_y;
|
||||
}
|
||||
|
||||
float TorusShape::getScaleFactor(float screen_height) const {
|
||||
auto TorusShape::getScaleFactor(float screen_height) const -> float {
|
||||
// Factor de escala para física: proporcional al radio mayor
|
||||
// Radio mayor base = 60px (0.25 * 240px en resolución 320x240)
|
||||
const float BASE_RADIUS = 60.0f;
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
// Comportamiento: Superficie toroidal con rotación triple (X, Y, Z)
|
||||
// Ecuaciones: x = (R + r*cos(v))*cos(u), y = (R + r*cos(v))*sin(u), z = r*sin(v)
|
||||
class TorusShape : public Shape {
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_z_ = 0.0f; // Ángulo de rotación en eje Z (rad)
|
||||
float major_radius_ = 0.0f; // Radio mayor R (del centro al tubo)
|
||||
float minor_radius_ = 0.0f; // Radio menor r (grosor del tubo)
|
||||
int num_points_ = 0; // Cantidad de puntos generados
|
||||
private:
|
||||
float angle_x_ = 0.0f; // Ángulo de rotación en eje X (rad)
|
||||
float angle_y_ = 0.0f; // Ángulo de rotación en eje Y (rad)
|
||||
float angle_z_ = 0.0f; // Ángulo de rotación en eje Z (rad)
|
||||
float major_radius_ = 0.0f; // Radio mayor R (del centro al tubo)
|
||||
float minor_radius_ = 0.0f; // Radio menor r (grosor del tubo)
|
||||
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 "TORUS"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
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 "TORUS"; }
|
||||
float getScaleFactor(float screen_height) const override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user