implements PLN-0026

This commit is contained in:
bQUARKz 2026-04-18 09:51:30 +01:00
parent b0b8bb9028
commit 4f52a65169
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 61 additions and 24 deletions

View File

@ -247,10 +247,15 @@ impl FrameComposer {
{
let update = resolver.update(scene, self.camera_x_px, self.camera_y_px);
Self::apply_refresh_requests(cache, scene, &update.refresh_requests);
// `FrameComposer` owns only canonical game-frame composition.
// Deferred `gfx.*` primitives are drained later by a separate
// overlay/debug stage outside this service boundary.
gfx.render_scene_from_cache(cache, &update);
return;
}
// No-scene frames still stop at canonical game composition. Final
// overlay/debug work remains outside `FrameComposer`.
gfx.render_no_scene_frame();
}

View File

@ -31,22 +31,11 @@ pub enum BlendMode {
/// PROMETEU Graphics Subsystem (GFX).
///
/// Models a specialized graphics chip with a fixed resolution, double buffering,
/// and a multi-layered tile/sprite architecture.
///
/// The GFX system works by composing several "layers" into a single 16-bit
/// RGB565 framebuffer. It supports hardware-accelerated primitives (lines, rects)
/// and specialized console features like background scrolling and sprite sorting.
///
/// ### Layer Composition Order (back to front):
/// 1. **Priority 0 Sprites**: Objects behind everything else.
/// 2. **Tile Layer 0 + Priority 1 Sprites**: Background 0.
/// 3. **Tile Layer 1 + Priority 2 Sprites**: Background 1.
/// 4. **Tile Layer 2 + Priority 3 Sprites**: Background 2.
/// 5. **Tile Layer 3 + Priority 4 Sprites**: Foreground.
/// 6. **Scene Fade**: Global brightness/color filter.
/// 7. **HUD Layer**: Fixed UI elements (always on top).
/// 8. **HUD Fade**: Independent fade for the UI.
/// `Gfx` owns the framebuffer backend and the canonical game-frame raster path
/// consumed by `FrameComposer`. That canonical path covers scene composition,
/// sprite composition, and fades. Public `gfx.*` primitives remain valid, but
/// they do not define the canonical game composition contract; they belong to a
/// separate final overlay/debug stage.
pub struct Gfx {
/// Width of the internal framebuffer in pixels.
w: usize,
@ -54,7 +43,8 @@ pub struct Gfx {
h: usize,
/// Front buffer: the "VRAM" currently being displayed by the Host window.
front: Vec<u16>,
/// Back buffer: the "Work RAM" where new frames are composed.
/// Back buffer: the working buffer where canonical game frames are composed
/// before any final overlay/debug drain.
back: Vec<u16>,
/// Shared access to graphical memory banks (tiles and palettes).

View File

@ -48,9 +48,21 @@ pub trait GfxBridge {
fn draw_horizontal_line(&mut self, x0: i32, x1: i32, y: i32, color: Color);
fn draw_vertical_line(&mut self, x: i32, y0: i32, y1: i32, color: Color);
fn present(&mut self);
/// Render the canonical game frame with no bound scene.
///
/// Deferred `gfx.*` overlay/debug primitives are intentionally outside this
/// contract and are drained by a separate final overlay stage.
fn render_no_scene_frame(&mut self);
/// Render the canonical scene-backed game frame from cache/resolver state.
///
/// Deferred `gfx.*` overlay/debug primitives are intentionally outside this
/// contract and are drained by a separate final overlay stage.
fn render_scene_from_cache(&mut self, cache: &SceneViewportCache, update: &ResolverUpdate);
fn load_frame_sprites(&mut self, sprites: &[Sprite]);
/// Submit text into the `gfx.*` primitive path.
///
/// Under the accepted runtime contract this is not the canonical game
/// composition path; it belongs to the deferred final overlay/debug family.
fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color);
fn draw_char(&mut self, x: i32, y: i32, c: char, color: Color);

View File

@ -48,10 +48,12 @@ The GFX maintains two buffers:
Per-frame flow:
1. The system draws to the back buffer
2. Calls `present()`
3. Buffers are swapped
4. The host displays the front buffer
1. The system prepares the logical frame
2. Canonical game composition is rendered into the back buffer
3. Deferred final overlay/debug primitives are drained on top of the completed game frame
4. Calls `present()`
5. Buffers are swapped
6. The host displays the front buffer
This guarantees:
@ -183,7 +185,7 @@ Access:
---
## 10. Projection to the Back Buffer
## 10. Canonical Game Projection to the Back Buffer
For each frame:
@ -198,6 +200,10 @@ For each frame:
3. Draw HUD layer last
This section describes only the canonical game composition path.
`gfx.*` primitives such as `draw_text`, `draw_line`, and `draw_disc` are not part of this canonical game projection order. In v1 they belong to a deferred final overlay/debug stage that is drained after canonical game composition is complete.
---
## 11. Drawing Order and Priority
@ -214,6 +220,15 @@ Base order:
4. Tile Layer 3
5. Sprites (by priority between layers)
6. HUD Layer
7. Scene Fade
8. HUD Fade
9. Deferred `gfx.*` overlay/debug primitives
Normative boundary:
- Items 1 through 8 belong to canonical game-frame composition.
- Item 9 is a separate overlay/debug stage.
- Deferred `gfx.*` primitives MUST NOT be interpreted as scene, sprite, or canonical HUD content.
---
@ -258,8 +273,9 @@ Everything is:
## 14. Where Blend is Applied
- Blending occurs during drawing
- The result goes directly to the back buffer
- There is no automatic post-composition
- For canonical game composition, the result goes to the back buffer during composition
- For deferred `gfx.*` overlay/debug primitives, the result is applied during the final overlay/debug drain stage
- There is no automatic GPU-style post-processing pipeline
---
@ -296,6 +312,8 @@ controls:
- **Scene Fade**: affects the entire scene (Tile Layers 03 + Sprites)
- **HUD Fade**: affects only the HUD Layer (always composed last)
In v1, deferred `gfx.*` overlay/debug primitives are drained after both fades and therefore are not themselves part of scene or HUD fade application.
The fade is implemented without continuous per-pixel alpha and without floats.
It uses a **discrete integer level** (0..31), which in practice produces an
"almost continuous" visual result in 320×180 pixel art.
@ -566,6 +584,18 @@ Fault boundary:
| `composer.set_camera` | `void` | no real operational failure path in v1 |
| `composer.emit_sprite` | `status:int` | explicit orchestration-domain operational rejection |
### 19.1.a Deferred overlay/debug semantics for `gfx.*`
The public `gfx.*` primitive family remains valid in v1, but its stable operational meaning is:
- deferred final overlay/debug composition;
- screen-space and pipeline-agnostic relative to `composer.*`;
- outside `FrameComposer`;
- above scene, sprites, and canonical HUD;
- drained after `hud_fade`.
This means callers MUST NOT rely on stable immediate writes to the working back buffer as the public contract for `gfx.draw_text(...)` or sibling primitives.
### 19.2 `composer.emit_sprite`
`composer.emit_sprite` returns `status:int`.