// shape_renderer.cpp - Implementació del renderizado de formes // © 2026 JailDesigner #include "core/rendering/shape_renderer.hpp" #include #include "core/defaults.hpp" #include "core/rendering/line_renderer.hpp" namespace Rendering { // Helper: aplicar rotación 3D a un point 2D (assumeix Z=0) static auto apply_3d_rotation(float x, float y, const Rotation3D& rot) -> Vec2 { float z = 0.0F; // Todos los points 2D comencen a Z=0 // Pitch (rotación eix X): cabeceo arriba/baix float cos_pitch = std::cos(rot.pitch); float sin_pitch = std::sin(rot.pitch); float y1 = (y * cos_pitch) - (z * sin_pitch); float z1 = (y * sin_pitch) + (z * cos_pitch); // Yaw (rotación eix Y): guiñada izquierda/derecha float cos_yaw = std::cos(rot.yaw); float sin_yaw = std::sin(rot.yaw); float x2 = (x * cos_yaw) + (z1 * sin_yaw); float z2 = (-x * sin_yaw) + (z1 * cos_yaw); // Roll (rotación eix Z): alabeo lateral float cos_roll = std::cos(rot.roll); float sin_roll = std::sin(rot.roll); float x3 = (x2 * cos_roll) - (y1 * sin_roll); float y3 = (x2 * sin_roll) + (y1 * cos_roll); // Proyecció perspectiva (Z-divide simple) // Naves quieren hacia el point de fuga (320, 240) a "infinit" (Z → +∞) // Z més grande = més lluny = més pequeño a pantalla constexpr float perspective_factor = 500.0F; float scale_factor = perspective_factor / (perspective_factor + z2); return {.x = x3 * scale_factor, .y = y3 * scale_factor}; } // Helper: transformar un point con rotación, scale i traslación static auto transform_point(const Vec2& point, const Vec2& shape_centre, const Vec2& position, float angle, float scale, const Rotation3D* rotation_3d) -> Vec2 { // 1. Centrar el point respecte al centro de la shape float centered_x = point.x - shape_centre.x; float centered_y = point.y - shape_centre.y; // 2. Aplicar rotación 3D (si es proporciona) if ((rotation_3d != nullptr) && rotation_3d->has_rotation()) { Vec2 rotated_3d = apply_3d_rotation(centered_x, centered_y, *rotation_3d); centered_x = rotated_3d.x; centered_y = rotated_3d.y; } // 3. Aplicar scale al point (después de rotación 3D) float scaled_x = centered_x * scale; float scaled_y = centered_y * scale; // 4. Aplicar rotación 2D (Z-axis, tradicional) // IMPORTANT: En el sistema original, angle=0 apunta AMUNT (no derecha) // Per això usem (angle - PI/2) per compensar // Pero aquí angle ya ve en el sistema correcte del juego float cos_a = std::cos(angle); float sin_a = std::sin(angle); float rotated_x = (scaled_x * cos_a) - (scaled_y * sin_a); float rotated_y = (scaled_x * sin_a) + (scaled_y * cos_a); // 5. Aplicar traslación a posición mundial return {.x = rotated_x + position.x, .y = rotated_y + position.y}; } void render_shape(Rendering::Renderer* renderer, const std::shared_ptr& shape, const Vec2& position, float angle, float scale, float progress, float brightness, const Rotation3D* rotation_3d, SDL_Color color) { if (!shape || !shape->isValid()) { return; } if (progress < 1.0F) { return; } const Vec2& SHAPE_CENTRE = shape->getCenter(); for (const auto& primitive : shape->get_primitives()) { if (primitive.type == Graphics::PrimitiveType::POLYLINE) { // POLYLINE: conectar puntos consecutivos. for (size_t i = 0; i < primitive.points.size() - 1; i++) { const Vec2 P1 = transform_point(primitive.points[i], SHAPE_CENTRE, position, angle, scale, rotation_3d); const Vec2 P2 = transform_point(primitive.points[i + 1], SHAPE_CENTRE, position, angle, scale, rotation_3d); linea(renderer, static_cast(P1.x), static_cast(P1.y), static_cast(P2.x), static_cast(P2.y), brightness, 0.0F, color); } } else if (primitive.points.size() >= 2) { // LINE const Vec2 P1 = transform_point(primitive.points[0], SHAPE_CENTRE, position, angle, scale, rotation_3d); const Vec2 P2 = transform_point(primitive.points[1], SHAPE_CENTRE, position, angle, scale, rotation_3d); linea(renderer, static_cast(P1.x), static_cast(P1.y), static_cast(P2.x), static_cast(P2.y), brightness, 0.0F, color); } } } } // namespace Rendering