Files
orni-attack/MIGRATION_PLAN.md
T
JailDesigner ba6fd00b54 Fase 7a: infraestructura SDL3 GPU (dormida, sin tocar runtime)
Preparacion del pipeline GPU. Codigo nuevo aislado en
core/rendering/gpu/; el runtime sigue usando SDL_Renderer hasta
Fase 7b. Tras 7a el juego sigue funcionando identico.

Shaders (shaders/):
- line.vert.glsl: vertex shader, transforma de pixeles logicos a NDC
  via uniform buffer LineUniforms{viewport_w, viewport_h}.
- line.frag.glsl: pinta el color RGBA interpolado.

Build:
- CMakeLists.txt: step nuevo que compila *.glsl a build/shaders/*.spv
  con glslc. ALL depende del target 'shaders' para incluirlo en cada
  build. Falla en cmake config si glslc no esta instalado.

Wrappers C++ (source/core/rendering/gpu/):
- gpu_device.hpp/cpp: GpuDevice, claim del window, loadShader desde
  .spv. Backends solicitados: Vulkan + Metal (sin DirectX).
- gpu_line_pipeline.hpp/cpp: GpuLinePipeline. Vertex layout
  (vec2 pos + vec4 color), primitive TRIANGLELIST (lineas como
  quads), alpha blending estandar, sin culling ni depth.
- gpu_frame_renderer.hpp/cpp: GpuFrameRenderer, API alto nivel:
  beginFrame / pushLine / endFrame. Extrusion perpendicular en CPU
  por linea (thickness libre por linea). Un draw call por frame
  con vertex+index buffers transitorios.

Plan: 7b swap del SDL_Renderer al GpuFrameRenderer en SDLManager.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 14:01:34 +02:00

140 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Plan de migración Orni Attack → SDL3 GPU + física vectorial
Documento maestro de la rama `rewrite/physics-gpu`. Resumen del progreso y
qué queda. Si pierdes el contexto de la sesión, **léeme primero**.
## Visión
Modernizar la base técnica del juego antes de tunear jugabilidad:
1. Limpiar legacy (polares, mezcla catalán/inglés, header guards).
2. Adoptar formato 16:9 (1280×720).
3. Importar subsistemas robustos de AEEA (audio, *input deferido*).
4. Implementar física vectorial 2D con rigid bodies + colisiones elásticas.
5. **Migrar renderizado a SDL3 GPU sin fallback** ([memoria: project-no-sdl-fallback](./.claude/projects/-home-sergio-gitea-orni-attack/memory/project_no_sdl_fallback.md)).
6. Postprocesado y color.
El tuning de feeling se hace al final, post-GPU.
## Estado actual
Rama de trabajo: **`rewrite/physics-gpu`** (pusheada a Gitea).
Tag de seguridad: **`beta-3.0`** (snapshot de `main` antes de empezar).
| Fase | Estado | Commits |
|---|---|---|
| 0 — Limpieza de código muerto (primitives, polígonos, Bresenham, polares) | ✅ | `6cf990b` |
| 1a — `Punt → Vec2` con operadores modernos | ✅ | `cd38101` |
| 1b — Renames de entidades + métodos virtuales a camelBack | ✅ | `ae5cc1c` |
| 1c — Renames de escenas | ✅ | `5871d29` |
| 1d — Renames effects/stage_system/locales | ✅ | `7ee359b` |
| 1e — Pragma once + locales restantes + comentarios castellano | ✅ | `bf83f16` |
| (fix) — clave YAML `quadrat → cuadrado` post-sweep | ✅ | `56533ca` |
| 2 — Cambio a 1280×720 (16:9) | ✅ | `a4f6a55` |
| 3 — Import del subsistema de Audio desde AEEA | ✅ | `ed98ef6` |
| **4** — Input parcial AEEA | ⏭️ **saltado** (decisión usuario) | — |
| 5 — Infraestructura física (`RigidBody`, `PhysicsWorld`) | ✅ | `0fd9360` |
| 6a+b — `body_` en Entity + `world_` en GameScene | ✅ | `0574077` |
| 6c — Migrar Ship | ✅ | `2fe22ff` |
| 6d — Migrar Enemy | ✅ | `27242f5` |
| 6e — Migrar Bullet | ✅ | `9993b2d` |
| **7a — Infra GPU (shaders + wrappers, runtime dormido)** | ✅ | (este commit) |
| 7b — Swap SDL_Renderer → SDL_GPUDevice (clear/present por GPU) | 🔲 | — |
| 7c — Pipeline de líneas (quads con thickness configurable) | 🔲 | — |
| 7d — Refactor de firmas (SDL_Renderer* → FrameContext*) | 🔲 | — |
| 7e — Cleanup + smoke test final | 🔲 | — |
| 8 — Postprocesado, color, paleta por tipo | 🔲 | — |
| 9 — Refactor de GameScene (2.877 LOC → módulos) | 🔲 | — |
| 10 — Tuning final de masa/restitución/damping | 🔲 | — |
## Lo que queda inmediato (Fase 7b)
**Swap del runtime de SDL_Renderer a SDL_GPUDevice.**
Fase 7a completada: infraestructura GPU dormida (no llamada en runtime aún).
- `shaders/line.{vert,frag}.glsl` → compilados en build a `build/shaders/*.spv`
(CMake step con `glslc`). Vertex layout: vec2 position + vec4 color.
Transformación a NDC vía uniform buffer `LineUniforms{viewport_w, viewport_h}`.
- `core/rendering/gpu/`:
- `GpuDevice`: claim del window, loadShader desde .spv.
- `GpuLinePipeline`: pipeline TRIANGLELIST con vertex layout + alpha blending.
- `GpuFrameRenderer`: API `beginFrame / pushLine / endFrame`.
Extrusión perpendicular en CPU por línea (thickness configurable libre).
Un draw call por frame con un vertex/index buffer transitorio.
Backend: Vulkan (Linux/Windows) y Metal (macOS). Sin DirectX.
Fase 7b siguiente:
1. En `SDLManager::iniciar`, sustituir `SDL_CreateRenderer` por
`Rendering::GPU::GpuFrameRenderer::init(window, 1280, 720)`.
2. `SDLManager::neteja(r,g,b)``gpu_renderer_.beginFrame(r/255, g/255, b/255)`.
3. `SDLManager::presenta()``gpu_renderer_.endFrame()`.
4. Borrar `renderer_` (SDL_Renderer*) del SDLManager.
5. Validar arranque con xvfb: pantalla negra (sin líneas todavía), sin crash.
Después de 7b el juego se verá NEGRO porque ningún sistema sabe pintar líneas
todavía. Eso se arregla en 7c (line_renderer apunta al pipeline GPU) y 7d
(refactor de firmas SDL_Renderer* → FrameContext*).
**Fase 10 (tuning)** queda pendiente para después de SDL3 GPU + postpro.
## Memoria del proyecto
Las preferencias y decisiones persistentes están en:
`~/.claude/projects/-home-sergio-gitea-orni-attack/memory/MEMORY.md` y los
archivos enlazados desde ahí. Léelos al empezar sesión nueva.
Resumen:
- **No fallback a SDL_Renderer** en Fase 7 — solo GPU o falla.
- **Naming**: `.clang-tidy` exige `CamelCase` tipos, `camelBack` métodos,
`lower_case_` miembros privados, `UPPER_CASE` constantes.
- **Costuras del título tras 16:9** son tuning artístico, no bug, post-Fase 10.
- **Push automático** tras cada commit en `rewrite/physics-gpu`.
- **Smoke test xvfb** (`timeout 5 xvfb-run -a ./build/orni 2>&1 | head -40`)
tras builds importantes para validar arranque.
## Convenciones técnicas
- **Lenguaje código**: inglés. **Lenguaje comentarios**: castellano. **Strings
de UI**: valenciano (preservados).
- **Coordenadas**: cartesianas (`Vec2`). Polares prohibidas (legacy).
- **Resolución lógica**: 1280×720. Constantes en `core/defaults.hpp`.
- **Audio**: import de AEEA. API: `Audio::get()->playSound/playMusic` con
crossfade y efectos.
- **Física**: `Physics::RigidBody` en `core/physics/rigid_body.hpp`,
`Physics::PhysicsWorld` en `core/physics/physics_world.hpp/.cpp`.
Entity tiene `body_` como member. Flujo tri-fase por frame en
`GameScene::update`:
1. `physics_world_.update(dt)` — integrar y resolver
2. `entity.postUpdate(dt)` — sincronizar mirror (center_, angle_)
3. Lógica del juego (input, AI, etc.) — aplica fuerzas/cambia velocity
## Cómo reanudar tras compactación
1. Lee este archivo.
2. Lee `MEMORY.md` (memorias persistentes).
3. `git log --oneline -20` para ver últimos commits.
4. `git status` para ver si hay trabajo en curso sin commitear.
5. Si la fase actual estaba a medias: continúa donde se quedó (este archivo
indica en qué fase estamos).
6. Tras cada commit, push automático: `git push origin rewrite/physics-gpu`.
## Configuración física actual (Fase 6e)
| Entidad | mass | radius (world) | restitution | linear_damping | angular_damping |
|---|---|---|---|---|---|
| Ship | 10.0 | 12 | 0.6 | 1.5 | 0.0 |
| Enemy Pentagon | 5.0 | 20 | 1.0 | 0.0 | 0.0 |
| Enemy Quadrat | 8.0 | 20 | 1.0 | 0.0 | 0.0 |
| Enemy Molinillo | 4.0 | 20 | 1.0 | 0.0 | 0.0 |
| Bullet | 0.5 | **0** (cinemática) | 0 | 0 | 0 |
| Wall (PLAYAREA bounds) | ∞ (estático) | — | — | — | — |
Nota: Bullet usa `radius=0` en el body físico para que no participe en las
colisiones del world (ni body-body ni bounds). El radio de gameplay
(`Defaults::Entities::BULLET_RADIUS = 3`) lo expone vía `getCollisionRadius()`
y lo consumen `check_collision` y la detección de salida del PLAYAREA en
`Bullet::update`.
Las paredes son implícitas: `physics_world_.setBounds(PLAYAREA)` en
`GameScene::init`. No son `RigidBody` separados, sino un AABB que rebota.