Nilton Constantino acd09a6468
add audio
2026-01-14 17:55:06 +00:00

600 lines
11 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.

< [Voltar](chapter-3.md) | [Sumário](table-of-contens.md) | [Adiante](chapter-5.md) >
# 🎨 **Periférico GFX (Sistema Gráfico)**
## 1. Visão Geral
O periférico **GFX** é responsável pela geração de imagem no PROMETEU.
Ele modela um **hardware gráfico simples**, inspirado em consoles clássicos
(SNES, CPS-2, Neo-Geo), priorizando:
- determinismo
- baixo custo computacional
- didática
- portabilidade
O GFX **não é uma GPU moderna**.
Ele é um dispositivo explícito, baseado em:
- framebuffer
- tilemaps
- banks de tiles
- sprites por prioridade
- composição por ordem de desenho
---
## 2. Resolução e Framebuffer
### Resolução base
- **320 × 180 pixels**
- proporção próxima de 16:9
- escalável pelo host (nearest-neighbor)
### Formato de pixel
- **RGB565**
- 5 bits Red
- 6 bits Green
- 5 bits Blue
- sem canal alpha
Transparência é feita por **color key**.
---
## 3. Double Buffering
O GFX mantém dois buffers:
- **Back Buffer** — onde o frame é construído
- **Front Buffer** — onde o frame é exibido
Fluxo por frame:
1. O sistema desenha no back buffer
2. Chama `present()`
3. Buffers são trocados
4. O host exibe o front buffer
Isso garante:
- ausência de tearing
- sincronização clara por frame
- comportamento determinístico
---
## 4. Estrutura Gráfica do PROMETEU
O mundo gráfico é composto por:
- Até **16 Tile Banks**
- **4 Tile Layers** (scrolláveis)
- **1 HUD Layer** (fixa, sempre por cima)
- Sprites com prioridade entre layers
### 4.1 Tile Banks
- Existem até **16 banks**
- Cada bank tem tamanho fixo de tile:
- 8×8, 16×16 ou 32×32
- Um bank é uma biblioteca de gráficos:
- ambiente
- personagens
- UI
- efeitos
### 4.2 Layers
- Existem:
- 4 Tile Layers
- 1 HUD Layer
- Cada layer aponta para **um único bank**
- Sprites podem usar **qualquer bank**
- HUD:
- não scrolla
- prioridade máxima
- geralmente usa tiles 8×8
---
## 5. Modelo Interno de uma Tile Layer
Uma Tile Layer **não é um bitmap de pixels**.
Ela é composta por:
- Um **Tilemap lógico** (índices de tiles)
- Um **Cache de Borda** (janela de tiles visíveis)
- Um **Offset de Scroll**
### Estrutura:
- `bank_id`
- `tile_size`
- `tilemap` (matriz grande)
- `scroll_x`, `scroll_y`
- `cache_origin_x`, `cache_origin_y`
- `cache_tiles[w][h]`
---
## 6. Tilemap Lógico
O tilemap representa o mundo:
Cada célula contém:
- `tile_id`
- `flip_x`
- `flip_y`
- `priority` (opcional)
- `palette_id` (opcional)
O tilemap pode ser muito maior que a tela.
---
## 7. Cache de Borda (Tile Cache)
O cache é uma janela de tiles ao redor da câmera.
Exemplo:
- Tela: 320×180
- Tiles 16×16 → 20×12 visíveis
- Cache: 22×14 (margem de 1 tile)
Ele guarda os tiles já resolvidos a partir do tilemap.
---
## 8. Atualização do Cache
A cada frame:
1. Calcular:
- `tile_x = scroll_x / tile_size`
- `tile_y = scroll_y / tile_size`
- `offset_x = scroll_x % tile_size`
- `offset_y = scroll_y % tile_size`
2. Se `tile_x` mudou:
- Avança `cache_origin_x`
- Recarrega apenas a nova coluna
3. Se `tile_y` mudou:
- Avança `cache_origin_y`
- Recarrega apenas a nova linha
Somente **uma linha e/ou coluna** é atualizada por frame.
---
## 9. Cache como Ring Buffer
O cache é circular:
- Não move dados fisicamente
- Apenas move índices lógicos
Acesso:
- `real_x = (cache_origin_x + logical_x) % cache_width`
- `real_y = (cache_origin_y + logical_y) % cache_height`
---
## 10. Projeção para o Back Buffer
Para cada frame:
1. Para cada Tile Layer, em ordem:
- Rasterizar tiles visíveis do cache
- Aplicar scroll, flip e transparência
- Escrever no back buffer
2. Desenhar sprites:
- Com prioridade entre layers
- Ordem de desenho define profundidade
3. Desenhar HUD layer por último
---
## 11. Ordem de Desenho e Prioridade
- Não existe Z-buffer
- Não existe sorting automático
- Quem desenha depois fica na frente
Ordem base:
1. Tile Layer 0
2. Tile Layer 1
3. Tile Layer 2
4. Tile Layer 3
5. Sprites (por prioridade entre layers)
6. HUD Layer
---
## 12. Transparência (Color Key)
- Um valor RGB565 é reservado como TRANSPARENT_KEY
- Pixels com essa cor não são desenhados
```
if src == TRANSPARENT_KEY:
skip
else:
draw
```
---
## 13. Color Math (Blending Discreto)
Inspirado no SNES.
Modos oficiais:
- `BLEND_NONE`
- `BLEND_HALF`
- `BLEND_HALF_PLUS`
- `BLEND_HALF_MINUS`
- `BLEND_FULL`
Sem alpha contínuo.
Sem blending arbitrário.
Tudo é:
- inteiro
- barato
- determinístico
---
## 14. Onde o Blend é Aplicado
- O blend ocorre durante o desenho
- O resultado vai direto para o back buffer
- Não existe composição posterior automática
---
## 15. O que o GFX NÃO suporta
Por design:
- Alpha contínuo
- RGBA framebuffer
- Shader
- Pipeline moderno de GPU
- HDR
- Gamma correction
---
## 16. Regra de Performance
- Layers:
- só atualizam borda ao cruzar tile
- nunca redesenham mundo inteiro
- Rasterização:
- sempre por frame, só área visível
- Sprites:
- sempre redesenhados por frame
---
## 17. PostFX Especial — Fade (Scene e HUD)
O PROMETEU suporta **fade gradual** como um PostFX especial, com dois controles
independentes:
- **Scene Fade**: afeta toda a cena (Tile Layers 03 + Sprites)
- **HUD Fade**: afeta apenas o HUD Layer (sempre composto por último)
O fade é implementado sem alpha contínuo por pixel e sem floats.
Ele usa um **nível inteiro discreto** (0..31), que na prática produz um resultado
visual “quase contínuo” em 320×180 pixel art.
---
### 17.1 Representação do Fade
Cada fade é representado por:
- `fade_level: u8` no intervalo **[0..31]**
- `0` → totalmente substituído pela cor de fade
- `31` → totalmente visível (sem fade)
- `fade_color: RGB565`
- cor para a qual a imagem será misturada
Registradores:
- `SCENE_FADE_LEVEL` (0..31)
- `SCENE_FADE_COLOR` (RGB565)
- `HUD_FADE_LEVEL` (0..31)
- `HUD_FADE_COLOR` (RGB565)
Casos comuns:
- Fade-out: `fade_color = BLACK`
- Flash/teleporte: `fade_color = WHITE`
- Efeitos especiais: qualquer cor RGB565
---
### 17.2 Operação de Fade (Mistura com Cor Arbitrária)
Para cada pixel RGB565 `src` e cor de fade `fc`, o pixel final `dst` é calculado por canal.
1) Extrair componentes:
- `src_r5`, `src_g6`, `src_b5`
- `fc_r5`, `fc_g6`, `fc_b5`
2) Aplicar mistura inteira:
```
src_weight = fade_level // 0..31
fc_weight = 31 - fade_level
r5 = (src_r5 * src_weight + fc_r5 * fc_weight) / 31
g6 = (src_g6 * src_weight + fc_g6 * fc_weight) / 31
b5 = (src_b5 * src_weight + fc_b5 * fc_weight) / 31
```
- `src_r5`, `src_g6`, `src_b5`
- `fc_r5`, `fc_g6`, `fc_b5`
3) Reempacotar:
```
dst = pack_rgb565(r5, g6, b5)
```
Observações:
- Operação determinística
- Somente inteiros
- Pode ser otimizada via LUT
---
### 17.3 Ordem de Aplicação no Frame
A composição do frame segue esta ordem:
1. Rasterizar **Tile Layers 03** → Back Buffer
2. Rasterizar **Sprites** conforme prioridade
3. (Opcional) Pipeline extra (Emission/Light/Glow etc.)
4. Aplicar **Scene Fade** usando:
- `SCENE_FADE_LEVEL`
- `SCENE_FADE_COLOR`
5. Rasterizar **HUD Layer**
6. Aplicar **HUD Fade** usando:
- `HUD_FADE_LEVEL`
- `HUD_FADE_COLOR`
7. `present()`
Regras:
- Scene Fade nunca afeta HUD
- HUD Fade nunca afeta a cena
---
### 17.4 Casos de Uso
- Troca de HUD:
- diminuir `HUD_FADE_LEVEL` até 0
- trocar HUD/tilemap
- aumentar `HUD_FADE_LEVEL` até 31
- Troca de área:
- diminuir `SCENE_FADE_LEVEL` até 0
- trocar cenário
- aumentar `SCENE_FADE_LEVEL` até 31
- Flash / dano / teleporte:
- usar `fade_color = WHITE` ou outra cor temática
---
## 18. Sistema de Paletas
### 18.1. Visão Geral
O PROMETEU utiliza **exclusivamente** gráficos indexados por paleta.
Não existe modo RGB direto por pixel.
Todo pixel gráfico é um **índice** que aponta para uma cor real em uma paleta.
Objetivos:
- reduzir uso de RAM e storage
- permitir troca de cores sem shader
- manter identidade retrô
- facilitar efeitos como variação, dano, dia/noite
---
### 18.2. Formato de Pixel
Cada pixel de um tile ou sprite é:
- **4 bits por pixel (4bpp)**
- valores: `0..15`
Regra fixa:
- Índice `0` = TRANSPARENTE
- Índices `1..15` = cores válidas da paleta
---
### 18.3. Estrutura de Paletas
Cada **Tile Bank** contém:
- Até **256 paletas**
- Cada paleta tem:
- **16 cores**
- cada cor em **RGB565 (u16)**
Tamanho:
- 1 paleta = 16 × 2 bytes = **32 bytes**
- 256 paletas = **8 KB por bank**
- 16 banks = **128 KB máximo de paletas**
---
### 18.4. Associação de Paleta
#### Regra Fundamental
- Cada **tile** usa **uma única paleta**
- Cada **sprite** usa **uma única paleta**
- A paleta deve ser informada **explicitamente** em todo draw
Não existe troca de paleta dentro do mesmo tile ou sprite.
---
### 18.5. Onde a Paleta é Definida
#### Tilemap
Cada célula do tilemap contém:
- `tile_id`
- `palette_id (u8)`
- `flip_x`
- `flip_y`
#### Sprite
Cada sprite draw contém:
- `bank_id`
- `tile_id`
- `palette_id (u8)`
- `x`, `y`
- `flip_x`, `flip_y`
- `priority`
---
### 18.6. Resolução de Cor
O pipeline funciona assim:
1. Ler pixel indexado do tile (valor 0..15)
2. Se índice == 0 → pixel transparente
3. Caso contrário:
- cor_real = paleta[palette_id][indice]
4. Aplicar:
- flip
- blend discreto
- escrita no back buffer
Ou seja:
```
pixel_index = tile_pixel(x,y)
if pixel_index == 0:
skip
else:
color = bank.palettes[palette_id][pixel_index]
draw(color)
```
---
### 18.7. Organização dos Tile Banks
Os Tile Banks são “assets fortes”:
- Tiles e paletas vivem juntos
- Exportação/importação sempre leva:
- tiles + paletas
- O hardware não impõe organização semântica:
- o agrupamento é decisão do criador
- Tooling e scripts podem criar convenções:
- ex.: paletas 0..15 = inimigos
- 16..31 = cenário
- etc.
---
### 18.8. Efeitos Possíveis com Paletas
Sem shader, é possível:
- Palette swap:
- inimigos com variação de cor
- Estados:
- dano, gelo, veneno, power-up
- Dia / noite:
- trocar paletas globalmente
- Biomas:
- mesma arte, clima diferente
- UI themes
Tudo isso sem mudar os tiles.
---
### 18.9. Limitações Artísticas
- Cada tile/sprite:
- máximo de 16 cores
- Gradientes suaves exigem:
- dithering
- blend discreto
- glow/emission
Essa limitação é intencional e faz parte da identidade do PROMETEU.
---
### 18.10. Métricas para Certificação (CAP)
O sistema pode medir:
- `palettes_loaded_total`
- `palettes_referenced_this_frame`
- `tiles_drawn_by_palette_id`
- `sprites_drawn_by_palette_id`
Isso permite:
- analisar custo artístico
- ensinar impacto de variedade excessiva
- sugerir boas práticas de coesão visual
---
## 19. Resumo
O GFX do PROMETEU é simples **por escolha**, não por limitação.
- Framebuffer RGB565 com double buffer
- Color key para transparência
- Blending discreto estilo SNES
- Até 16 tile banks
- 4 Tile Layers + 1 HUD
- Layer = tilemap + cache + scroll
- Projeção rasterizada por frame
- Profundidade definida por ordem de desenho
< [Voltar](chapter-3.md) | [Sumário](table-of-contens.md) | [Adiante](chapter-5.md) >