From 57439846c5284a0be1f0eac459d7f9c4a963d507 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Mon, 25 May 2026 14:07:41 +0100 Subject: [PATCH] implements PLN-0078 Classic2D packet consumer --- crates/console/prometeu-drivers/src/gfx.rs | 72 ++++++++++++++++++- .../console/prometeu-drivers/src/hardware.rs | 7 +- discussion/index.ndjson | 2 +- ...N-0078-classic2d-game-renderer-consumer.md | 2 +- 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/crates/console/prometeu-drivers/src/gfx.rs b/crates/console/prometeu-drivers/src/gfx.rs index 3ebf43f3..22b6ff47 100644 --- a/crates/console/prometeu-drivers/src/gfx.rs +++ b/crates/console/prometeu-drivers/src/gfx.rs @@ -1,11 +1,11 @@ use crate::memory_banks::GlyphBankPoolAccess; -use prometeu_hal::GfxBridge; use prometeu_hal::color::Color; use prometeu_hal::glyph::Glyph; use prometeu_hal::glyph_bank::GlyphBank; use prometeu_hal::scene_viewport_cache::{CachedTileEntry, SceneViewportCache}; use prometeu_hal::scene_viewport_resolver::{LayerCopyRequest, ResolverUpdate}; use prometeu_hal::sprite::Sprite; +use prometeu_hal::{Game2DFramePacket, Gfx2dCommand, GfxBridge}; use std::sync::Arc; /// Blending modes inspired by classic 16-bit hardware. @@ -686,6 +686,58 @@ impl Gfx { Self::apply_fade_to_buffer(&mut self.back, self.hud_fade_level, self.hud_fade_color); } + pub fn render_game2d_frame_packet(&mut self, packet: &Game2DFramePacket) { + let sprites: Vec = packet + .composer + .sprites + .iter() + .map(|sprite| Sprite { + glyph: Glyph { + glyph_id: sprite.glyph_id as u16, + palette_id: sprite.palette_id as u8, + }, + x: sprite.x, + y: sprite.y, + layer: sprite.layer as u8, + bank_id: sprite.bank_id as u8, + active: true, + flip_x: sprite.flip_x, + flip_y: sprite.flip_y, + priority: sprite.priority as u8, + }) + .collect(); + self.load_frame_sprites(&sprites); + self.render_no_scene_frame(); + + for command in &packet.gfx2d { + self.apply_gfx2d_command(command); + } + } + + fn apply_gfx2d_command(&mut self, command: &Gfx2dCommand) { + match command { + Gfx2dCommand::Clear { color } => self.clear(*color), + Gfx2dCommand::FillRect { rect, color } => { + self.fill_rect(rect.x, rect.y, rect.w, rect.h, *color); + } + Gfx2dCommand::DrawLine { x0, y0, x1, y1, color } => { + self.draw_line(*x0, *y0, *x1, *y1, *color); + } + Gfx2dCommand::DrawCircle { x, y, radius, color } => { + self.draw_circle(*x, *y, *radius, *color); + } + Gfx2dCommand::DrawDisc { x, y, radius, border_color, fill_color } => { + self.draw_disc(*x, *y, *radius, *border_color, *fill_color); + } + Gfx2dCommand::DrawSquare { rect, border_color, fill_color } => { + self.draw_square(rect.x, rect.y, rect.w, rect.h, *border_color, *fill_color); + } + Gfx2dCommand::DrawText { x, y, text, color } => { + self.draw_text(*x, *y, text, *color); + } + } + } + fn populate_layer_buckets(&mut self) { for bucket in self.layer_buckets.iter_mut() { bucket.clear(); @@ -1331,4 +1383,22 @@ mod tests { assert_eq!(gfx.sprites[0].layer, 1); assert_eq!(gfx.sprites[1].glyph.glyph_id, 5); } + + #[test] + fn render_game2d_frame_packet_applies_primitive_commands() { + let mut gfx = Gfx::new(8, 8, Arc::new(MemoryBanks::default())); + let packet = Game2DFramePacket::new( + Default::default(), + vec![Gfx2dCommand::FillRect { + rect: prometeu_hal::primitives::Rect { x: 1, y: 1, w: 2, h: 2 }, + color: Color::RED, + }], + ); + + gfx.render_game2d_frame_packet(&packet); + gfx.present(); + + assert_eq!(gfx.front_buffer()[1 + 8], Color::RED.raw()); + assert_eq!(gfx.front_buffer()[2 + 2 * 8], Color::RED.raw()); + } } diff --git a/crates/console/prometeu-drivers/src/hardware.rs b/crates/console/prometeu-drivers/src/hardware.rs index 590002f0..724ba47f 100644 --- a/crates/console/prometeu-drivers/src/hardware.rs +++ b/crates/console/prometeu-drivers/src/hardware.rs @@ -73,7 +73,12 @@ impl HardwareBridge for Hardware { } fn render_frame(&mut self) { - self.frame_composer.render_frame(&mut self.gfx); + if self.frame_composer.active_scene_id().is_none() { + let packet = self.frame_composer.close_game2d_packet(); + self.gfx.render_game2d_frame_packet(&packet); + } else { + self.frame_composer.render_frame(&mut self.gfx); + } } fn has_glyph_bank(&self, bank_id: usize) -> bool { diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 5be067d1..c39fc9e5 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,5 +1,5 @@ {"type":"meta","next_id":{"DSC":39,"AGD":39,"DEC":31,"PLN":87,"LSN":47,"CLSN":1}} -{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]} {"type":"discussion","id":"DSC-0035","status":"done","ticket":"task-owned-shell-windows","title":"Agenda - Task-Owned Shell Windows","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","task","window-manager","shell","lifecycle"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0044","file":"discussion/lessons/DSC-0035-task-owned-shell-windows/LSN-0044-task-window-liveness-belongs-to-the-task.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0034","status":"done","ticket":"system-os-domain-facades","title":"Agenda - SystemOS Domain Facades","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","services","api-surface","lifecycle","fs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0043","file":"discussion/lessons/DSC-0034-system-os-domain-facades/LSN-0043-systemos-domain-facades.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"discussion/lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]} diff --git a/discussion/workflow/plans/PLN-0078-classic2d-game-renderer-consumer.md b/discussion/workflow/plans/PLN-0078-classic2d-game-renderer-consumer.md index 9ed855f7..2fd592db 100644 --- a/discussion/workflow/plans/PLN-0078-classic2d-game-renderer-consumer.md +++ b/discussion/workflow/plans/PLN-0078-classic2d-game-renderer-consumer.md @@ -2,7 +2,7 @@ id: PLN-0078 ticket: render-frame-packet-boundary title: Classic2D Game Renderer Consumer -status: open +status: done created: 2026-05-25 ref_decisions: [DEC-0030] tags: [gfx, renderer, runtime, frame-composer, architecture, ui, pipeline]