8.2 KiB
Raw Blame History

< Voltar | Sumário | Adiante >

🎨 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 Game 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 Game 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 Game Layer

Uma Game 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
  1. Se tile_x mudou:
  • Avança cache_origin_x
  • Recarrega apenas a nova coluna
  1. 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 Game Layer, em ordem:
  • Rasterizar tiles visíveis do cache
  • Aplicar scroll, flip e transparência
  • Escrever no back buffer
  1. Desenhar sprites:
  • Com prioridade entre layers
  • Ordem de desenho define profundidade
  1. 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. Game Layer 0
  2. Game Layer 1
  3. Game Layer 2
  4. Game 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 (Game 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
  1. 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
  1. 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

  1. 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 Game 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
  1. Rasterizar HUD Layer
  2. Aplicar HUD Fade usando:
  • HUD_FADE_LEVEL
  • HUD_FADE_COLOR
  1. 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. 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 game layers + 1 HUD
  • Layer = tilemap + cache + scroll
  • Projeção rasterizada por frame
  • Profundidade definida por ordem de desenho

< Voltar | Sumário | Adiante >