// shape_renderer.cpp - Implementació del renderitzat de formes // © 2025 Port a C++20 amb SDL3 #include "core/rendering/shape_renderer.hpp" #include #include "core/defaults.hpp" #include "core/rendering/line_renderer.hpp" namespace Rendering { // Helper: aplicar rotació 3D a un punt 2D (assumeix Z=0) static Punt apply_3d_rotation(float x, float y, const Rotation3D& rot) { float z = 0.0f; // Tots els punts 2D comencen a Z=0 // Pitch (rotació 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ó eix Y): guiñada esquerra/dreta 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ó 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) // Naus volen cap al punt de fuga (320, 240) a "infinit" (Z → +∞) // Z més gran = més lluny = més petit a pantalla constexpr float perspective_factor = 500.0f; float scale_factor = perspective_factor / (perspective_factor + z2); return {x3 * scale_factor, y3 * scale_factor}; } // Helper: transformar un punt amb rotació, escala i trasllació static Punt transform_point(const Punt& point, const Punt& shape_centre, const Punt& posicio, float angle, float escala, const Rotation3D* rotation_3d) { // 1. Centrar el punt respecte al centre de la forma float centered_x = point.x - shape_centre.x; float centered_y = point.y - shape_centre.y; // 2. Aplicar rotació 3D (si es proporciona) if (rotation_3d && rotation_3d->has_rotation()) { Punt rotated_3d = apply_3d_rotation(centered_x, centered_y, *rotation_3d); centered_x = rotated_3d.x; centered_y = rotated_3d.y; } // 3. Aplicar escala al punt (després de rotació 3D) float scaled_x = centered_x * escala; float scaled_y = centered_y * escala; // 4. Aplicar rotació 2D (Z-axis, tradicional) // IMPORTANT: En el sistema original, angle=0 apunta AMUNT (no dreta) // Per això usem (angle - PI/2) per compensar // Però aquí angle ja ve en el sistema correcte del joc 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 trasllació a posició mundial return {rotated_x + posicio.x, rotated_y + posicio.y}; } void render_shape(SDL_Renderer* renderer, const std::shared_ptr& shape, const Punt& posicio, float angle, float escala, bool dibuixar, float progress, float brightness, const Rotation3D* rotation_3d) { // Verificar que la forma és vàlida if (!shape || !shape->es_valida()) { return; } // Si progress < 1.0, no dibuixar (tot o res) if (progress < 1.0f) { return; } // Obtenir el centre de la forma per a transformacions const Punt& shape_centre = shape->get_centre(); // Iterar sobre totes les primitives for (const auto& primitive : shape->get_primitives()) { if (primitive.type == Graphics::PrimitiveType::POLYLINE) { // POLYLINE: connectar punts consecutius for (size_t i = 0; i < primitive.points.size() - 1; i++) { Punt p1 = transform_point(primitive.points[i], shape_centre, posicio, angle, escala, rotation_3d); Punt p2 = transform_point(primitive.points[i + 1], shape_centre, posicio, angle, escala, rotation_3d); linea(renderer, static_cast(p1.x), static_cast(p1.y), static_cast(p2.x), static_cast(p2.y), dibuixar, brightness); } } else { // PrimitiveType::LINE // LINE: exactament 2 punts if (primitive.points.size() >= 2) { Punt p1 = transform_point(primitive.points[0], shape_centre, posicio, angle, escala, rotation_3d); Punt p2 = transform_point(primitive.points[1], shape_centre, posicio, angle, escala, rotation_3d); linea(renderer, static_cast(p1.x), static_cast(p1.y), static_cast(p2.x), static_cast(p2.y), dibuixar, brightness); } } } } } // namespace Rendering