fad4006f60
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
163 lines
4.9 KiB
Markdown
163 lines
4.9 KiB
Markdown
---
|
|
id: "0072c"
|
|
title: "gamedev — asset pipeline (atlas packer, MSDF fonts, tilemap, shader translate)"
|
|
status: pendiente
|
|
type: feature
|
|
domain:
|
|
- gamedev
|
|
scope: multi-app
|
|
priority: alta
|
|
depends:
|
|
- "0072b"
|
|
blocks: []
|
|
related: []
|
|
created: 2026-05-10
|
|
updated: 2026-05-17
|
|
tags:
|
|
- gamedev
|
|
- cpp
|
|
- assets
|
|
---
|
|
|
|
## Objetivo
|
|
|
|
Pipeline de procesamiento de assets que corre en host (PC) y produce ficheros binarios listos para que el runtime los cargue rapido y pequeño. Sin assets crudos en el bundle final.
|
|
|
|
## Funciones a crear
|
|
|
|
### Sprite atlas packer
|
|
|
|
`sprite_atlas_pack_cpp_gfx` (impure):
|
|
|
|
```cpp
|
|
struct AtlasInput {
|
|
std::vector<std::string> png_paths;
|
|
int max_size = 2048;
|
|
int padding = 2;
|
|
};
|
|
|
|
struct AtlasOutput {
|
|
std::vector<uint8_t> png_bytes; // atlas final
|
|
std::vector<SpriteRect> rects; // {name, x, y, w, h, trim_x, trim_y, src_w, src_h}
|
|
};
|
|
|
|
AtlasOutput sprite_atlas_pack(const AtlasInput& in);
|
|
void atlas_save(const std::string& dir, const std::string& name, const AtlasOutput& a);
|
|
```
|
|
|
|
Algoritmo: MaxRects (skyline). Soporta trim (recorte de pixeles transparentes). Salida: `<name>.png` + `<name>.json` con rects.
|
|
|
|
### MSDF fonts
|
|
|
|
`ttf_to_msdf_cpp_gfx` (impure). Convierte TTF a Multi-channel Signed Distance Field. Glyphs crisp en cualquier zoom sin antialiasing pesado.
|
|
|
|
Vendoring: `msdf-atlas-gen` (MIT). Wrapper minimo:
|
|
|
|
```cpp
|
|
struct MsdfFontOutput {
|
|
std::vector<uint8_t> png_bytes;
|
|
std::vector<GlyphInfo> glyphs; // {codepoint, plane_bounds, atlas_bounds, advance}
|
|
float em_size, line_height, ascender, descender;
|
|
};
|
|
|
|
MsdfFontOutput ttf_to_msdf(const std::string& ttf_path,
|
|
const std::vector<uint32_t>& charset,
|
|
int atlas_size = 512);
|
|
```
|
|
|
|
### Tilemap compile
|
|
|
|
`tilemap_compile_cpp_gfx` (impure). Lee Tiled `.tmx` (XML) o `.tmj` (JSON) y produce binario empaquetado:
|
|
|
|
```
|
|
[header: width, height, tile_size, layer_count, tileset_count]
|
|
[tilesets: png_path, tile_w, tile_h, columns, tile_count]
|
|
[layers: name, opacity, data_size, RLE-compressed gids]
|
|
[objects: id, type, x, y, w, h, props_json]
|
|
```
|
|
|
|
Vendoring: `tinyxml2` o `nlohmann/json` (uno de los dos, ya en stack).
|
|
|
|
### Shader translate
|
|
|
|
`shader_translate_cpp_gfx` (impure). Cross-compila GLSL → MSL (Metal) / HLSL / WGSL / GLES via SPIRV-Cross + glslang.
|
|
|
|
Plan B si SPIRV-Cross es muy pesado: definir subset GLSL ES 300 que es valido en GL desktop, GLES, WebGL2 (sokol_gfx ya hace de ese subset trabajo). Documentar reglas en `cpp/GAMEDEV.md`.
|
|
|
|
### Audio encode
|
|
|
|
`audio_encode_cpp_gfx` (impure). Convierte wav → ogg vorbis o opus. Vendoring: `stb_vorbis` (decode), `libogg`+`libvorbis` para encode (opcional, primer paso es solo wav loading).
|
|
|
|
### Bundle packer
|
|
|
|
`asset_bundle_pack_cpp_gfx` (impure). Toma directorio `assets/` y produce un `.pak` binario con:
|
|
- Header: magic + version + asset count
|
|
- TOC: name → offset, size, hash
|
|
- Concatenacion de ficheros
|
|
|
|
Runtime carga el `.pak` en memoria una vez y lookup por nombre. Para WASM se embebe via `--preload-file` o via `--embed-file` segun tamaño.
|
|
|
|
## CLI app: `asset_compiler`
|
|
|
|
`cpp/apps/asset_compiler/` — CLI que compone las funciones:
|
|
|
|
```bash
|
|
./asset_compiler atlas --in sprites/ --out build/atlas.pak --max-size 2048
|
|
./asset_compiler font --in fonts/Roboto.ttf --out build/font_roboto.msdf
|
|
./asset_compiler tilemap --in levels/level1.tmx --out build/level1.bin
|
|
./asset_compiler bundle --in build/ --out game_assets.pak
|
|
```
|
|
|
|
Pipeline completo: `bash/functions/pipelines/build_assets_cpp_gamedev.sh` que llama `asset_compiler` para cada tipo y produce el bundle final.
|
|
|
|
## Estructura
|
|
|
|
```
|
|
cpp/functions/gfx/
|
|
sprite_atlas_pack.{cpp,h,md}
|
|
ttf_to_msdf.{cpp,h,md}
|
|
tilemap_compile.{cpp,h,md}
|
|
shader_translate.{cpp,h,md}
|
|
audio_encode.{cpp,h,md}
|
|
asset_bundle_pack.{cpp,h,md}
|
|
|
|
cpp/apps/asset_compiler/
|
|
CMakeLists.txt
|
|
app.md
|
|
main.cpp
|
|
data.{cpp,h} # CRUD de bundles
|
|
```
|
|
|
|
## Vendoring
|
|
|
|
Añadir a `cpp/vendor/`:
|
|
- `msdf-atlas-gen` (MIT) — fonts
|
|
- `stb_rect_pack.h` — atlas packing
|
|
- `tinyxml2.h/.cpp` — Tiled tmx
|
|
- `SPIRV-Cross` (opcional, decision en sub-issue propio si pesa demasiado)
|
|
|
|
Cada vendor en subdir propio + `LICENSE.txt`.
|
|
|
|
## Tamaño
|
|
|
|
Asset compiler corre en host, NO afecta runtime size. Pero los formatos elegidos SI:
|
|
- Atlas PNG → cargar con stb_image (ya en runtime).
|
|
- MSDF PNG → mismo.
|
|
- Tilemap binario → loader propio, ~100 LoC.
|
|
- `.pak` → loader propio, ~150 LoC.
|
|
|
|
Total runtime nuevo: ≤ 50 KB.
|
|
|
|
## Criterio de exito
|
|
|
|
- [x] `asset_compiler` produce bundle desde una carpeta de prueba.
|
|
- [x] Runtime (ya en 0072b) carga `.pak` y muestra atlas + texto MSDF + tilemap.
|
|
- [x] Tiempo de carga `.pak` < 500ms para 10MB de assets en navegador.
|
|
- [x] Tests por funcion (atlas pack determinista, msdf coverage, tilemap roundtrip).
|
|
|
|
## No-objetivos
|
|
|
|
- Hot reload de assets (en 0072i editor).
|
|
- Compresion del bundle (lz4/zstd) — si hace falta despues.
|
|
- Streaming de assets — overkill por ahora.
|