dev/render-all-scene-cache-and-camera-integration #16
@ -1,3 +1,4 @@
|
|||||||
|
use crate::gfx_overlay::{DeferredGfxOverlay, OverlayCommand};
|
||||||
use crate::memory_banks::GlyphBankPoolAccess;
|
use crate::memory_banks::GlyphBankPoolAccess;
|
||||||
use prometeu_hal::GfxBridge;
|
use prometeu_hal::GfxBridge;
|
||||||
use prometeu_hal::color::Color;
|
use prometeu_hal::color::Color;
|
||||||
@ -49,6 +50,8 @@ pub struct Gfx {
|
|||||||
|
|
||||||
/// Shared access to graphical memory banks (tiles and palettes).
|
/// Shared access to graphical memory banks (tiles and palettes).
|
||||||
pub glyph_banks: Arc<dyn GlyphBankPoolAccess>,
|
pub glyph_banks: Arc<dyn GlyphBankPoolAccess>,
|
||||||
|
/// Deferred overlay/debug capture kept separate from canonical game composition.
|
||||||
|
overlay: DeferredGfxOverlay,
|
||||||
/// Hardware sprite list (512 slots). Equivalent to OAM (Object Attribute Memory).
|
/// Hardware sprite list (512 slots). Equivalent to OAM (Object Attribute Memory).
|
||||||
pub sprites: [Sprite; 512],
|
pub sprites: [Sprite; 512],
|
||||||
|
|
||||||
@ -288,6 +291,7 @@ impl Gfx {
|
|||||||
front: vec![0; len],
|
front: vec![0; len],
|
||||||
back: vec![0; len],
|
back: vec![0; len],
|
||||||
glyph_banks,
|
glyph_banks,
|
||||||
|
overlay: DeferredGfxOverlay::default(),
|
||||||
sprites: [EMPTY_SPRITE; 512],
|
sprites: [EMPTY_SPRITE; 512],
|
||||||
sprite_count: 0,
|
sprite_count: 0,
|
||||||
scene_fade_level: 31,
|
scene_fade_level: 31,
|
||||||
@ -307,6 +311,14 @@ impl Gfx {
|
|||||||
(self.w, self.h)
|
(self.w, self.h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn begin_overlay_frame(&mut self) {
|
||||||
|
self.overlay.begin_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn overlay(&self) -> &DeferredGfxOverlay {
|
||||||
|
&self.overlay
|
||||||
|
}
|
||||||
|
|
||||||
/// The buffer that the host should display (RGB565).
|
/// The buffer that the host should display (RGB565).
|
||||||
pub fn front_buffer(&self) -> &[u16] {
|
pub fn front_buffer(&self) -> &[u16] {
|
||||||
&self.front
|
&self.front
|
||||||
@ -326,6 +338,7 @@ impl Gfx {
|
|||||||
color: Color,
|
color: Color,
|
||||||
mode: BlendMode,
|
mode: BlendMode,
|
||||||
) {
|
) {
|
||||||
|
self.overlay.push(OverlayCommand::FillRectBlend { x, y, w, h, color, mode });
|
||||||
if color == Color::COLOR_KEY {
|
if color == Color::COLOR_KEY {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -367,6 +380,7 @@ impl Gfx {
|
|||||||
|
|
||||||
/// Draws a line between two points using Bresenham's algorithm.
|
/// Draws a line between two points using Bresenham's algorithm.
|
||||||
pub fn draw_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color) {
|
pub fn draw_line(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, color: Color) {
|
||||||
|
self.overlay.push(OverlayCommand::DrawLine { x0, y0, x1, y1, color });
|
||||||
if color == Color::COLOR_KEY {
|
if color == Color::COLOR_KEY {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -399,6 +413,7 @@ impl Gfx {
|
|||||||
|
|
||||||
/// Draws a circle outline using Midpoint Circle Algorithm.
|
/// Draws a circle outline using Midpoint Circle Algorithm.
|
||||||
pub fn draw_circle(&mut self, xc: i32, yc: i32, r: i32, color: Color) {
|
pub fn draw_circle(&mut self, xc: i32, yc: i32, r: i32, color: Color) {
|
||||||
|
self.overlay.push(OverlayCommand::DrawCircle { x: xc, y: yc, r, color });
|
||||||
if color == Color::COLOR_KEY {
|
if color == Color::COLOR_KEY {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -467,6 +482,7 @@ impl Gfx {
|
|||||||
|
|
||||||
/// Draws a disc (filled circle with border).
|
/// Draws a disc (filled circle with border).
|
||||||
pub fn draw_disc(&mut self, x: i32, y: i32, r: i32, border_color: Color, fill_color: Color) {
|
pub fn draw_disc(&mut self, x: i32, y: i32, r: i32, border_color: Color, fill_color: Color) {
|
||||||
|
self.overlay.push(OverlayCommand::DrawDisc { x, y, r, border_color, fill_color });
|
||||||
self.fill_circle(x, y, r, fill_color);
|
self.fill_circle(x, y, r, fill_color);
|
||||||
self.draw_circle(x, y, r, border_color);
|
self.draw_circle(x, y, r, border_color);
|
||||||
}
|
}
|
||||||
@ -496,6 +512,7 @@ impl Gfx {
|
|||||||
border_color: Color,
|
border_color: Color,
|
||||||
fill_color: Color,
|
fill_color: Color,
|
||||||
) {
|
) {
|
||||||
|
self.overlay.push(OverlayCommand::DrawSquare { x, y, w, h, border_color, fill_color });
|
||||||
self.fill_rect(x, y, w, h, fill_color);
|
self.fill_rect(x, y, w, h, fill_color);
|
||||||
self.draw_rect(x, y, w, h, border_color);
|
self.draw_rect(x, y, w, h, border_color);
|
||||||
}
|
}
|
||||||
@ -783,6 +800,7 @@ impl Gfx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color) {
|
pub fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color) {
|
||||||
|
self.overlay.push(OverlayCommand::DrawText { x, y, text: text.to_string(), color });
|
||||||
let mut cx = x;
|
let mut cx = x;
|
||||||
for c in text.chars() {
|
for c in text.chars() {
|
||||||
self.draw_char(cx, y, c, color);
|
self.draw_char(cx, y, c, color);
|
||||||
@ -827,7 +845,8 @@ impl Gfx {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::memory_banks::{GlyphBankPoolInstaller, MemoryBanks};
|
use crate::FrameComposer;
|
||||||
|
use crate::memory_banks::{GlyphBankPoolInstaller, MemoryBanks, SceneBankPoolAccess};
|
||||||
use prometeu_hal::glyph_bank::TileSize;
|
use prometeu_hal::glyph_bank::TileSize;
|
||||||
use prometeu_hal::scene_bank::SceneBank;
|
use prometeu_hal::scene_bank::SceneBank;
|
||||||
use prometeu_hal::scene_layer::{ParallaxFactor, SceneLayer};
|
use prometeu_hal::scene_layer::{ParallaxFactor, SceneLayer};
|
||||||
@ -926,9 +945,14 @@ mod tests {
|
|||||||
fn test_draw_line() {
|
fn test_draw_line() {
|
||||||
let banks = Arc::new(MemoryBanks::new());
|
let banks = Arc::new(MemoryBanks::new());
|
||||||
let mut gfx = Gfx::new(10, 10, banks);
|
let mut gfx = Gfx::new(10, 10, banks);
|
||||||
|
gfx.begin_overlay_frame();
|
||||||
gfx.draw_line(0, 0, 9, 9, Color::WHITE);
|
gfx.draw_line(0, 0, 9, 9, Color::WHITE);
|
||||||
assert_eq!(gfx.back[0], Color::WHITE.0);
|
assert_eq!(gfx.back[0], Color::WHITE.0);
|
||||||
assert_eq!(gfx.back[9 * 10 + 9], Color::WHITE.0);
|
assert_eq!(gfx.back[9 * 10 + 9], Color::WHITE.0);
|
||||||
|
assert_eq!(
|
||||||
|
gfx.overlay().commands(),
|
||||||
|
&[OverlayCommand::DrawLine { x0: 0, y0: 0, x1: 9, y1: 9, color: Color::WHITE }]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -954,11 +978,53 @@ mod tests {
|
|||||||
fn test_draw_square() {
|
fn test_draw_square() {
|
||||||
let banks = Arc::new(MemoryBanks::new());
|
let banks = Arc::new(MemoryBanks::new());
|
||||||
let mut gfx = Gfx::new(10, 10, banks);
|
let mut gfx = Gfx::new(10, 10, banks);
|
||||||
|
gfx.begin_overlay_frame();
|
||||||
gfx.draw_square(2, 2, 6, 6, Color::WHITE, Color::BLACK);
|
gfx.draw_square(2, 2, 6, 6, Color::WHITE, Color::BLACK);
|
||||||
// Border
|
// Border
|
||||||
assert_eq!(gfx.back[2 * 10 + 2], Color::WHITE.0);
|
assert_eq!(gfx.back[2 * 10 + 2], Color::WHITE.0);
|
||||||
// Fill
|
// Fill
|
||||||
assert_eq!(gfx.back[3 * 10 + 3], Color::BLACK.0);
|
assert_eq!(gfx.back[3 * 10 + 3], Color::BLACK.0);
|
||||||
|
assert_eq!(gfx.overlay().command_count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn draw_text_captures_overlay_command() {
|
||||||
|
let banks = Arc::new(MemoryBanks::new());
|
||||||
|
let mut gfx = Gfx::new(32, 18, banks);
|
||||||
|
gfx.begin_overlay_frame();
|
||||||
|
|
||||||
|
gfx.draw_text(4, 5, "HUD", Color::WHITE);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
gfx.overlay().commands(),
|
||||||
|
&[OverlayCommand::DrawText { x: 4, y: 5, text: "HUD".into(), color: Color::WHITE }]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn overlay_state_is_separate_from_frame_composer_sprite_state() {
|
||||||
|
let banks = Arc::new(MemoryBanks::new());
|
||||||
|
let mut gfx = Gfx::new(32, 18, Arc::clone(&banks) as Arc<dyn GlyphBankPoolAccess>);
|
||||||
|
let mut frame_composer =
|
||||||
|
FrameComposer::new(32, 18, Arc::clone(&banks) as Arc<dyn SceneBankPoolAccess>);
|
||||||
|
|
||||||
|
gfx.begin_overlay_frame();
|
||||||
|
frame_composer.begin_frame();
|
||||||
|
frame_composer.emit_sprite(Sprite {
|
||||||
|
glyph: Glyph { glyph_id: 0, palette_id: 0 },
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
layer: 0,
|
||||||
|
bank_id: 0,
|
||||||
|
active: true,
|
||||||
|
flip_x: false,
|
||||||
|
flip_y: false,
|
||||||
|
priority: 0,
|
||||||
|
});
|
||||||
|
gfx.draw_text(1, 1, "X", Color::WHITE);
|
||||||
|
|
||||||
|
assert_eq!(frame_composer.sprite_controller().sprite_count(), 1);
|
||||||
|
assert_eq!(gfx.overlay().command_count(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
35
crates/console/prometeu-drivers/src/gfx_overlay.rs
Normal file
35
crates/console/prometeu-drivers/src/gfx_overlay.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::gfx::BlendMode;
|
||||||
|
use prometeu_hal::color::Color;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum OverlayCommand {
|
||||||
|
FillRectBlend { x: i32, y: i32, w: i32, h: i32, color: Color, mode: BlendMode },
|
||||||
|
DrawLine { x0: i32, y0: i32, x1: i32, y1: i32, color: Color },
|
||||||
|
DrawCircle { x: i32, y: i32, r: i32, color: Color },
|
||||||
|
DrawDisc { x: i32, y: i32, r: i32, border_color: Color, fill_color: Color },
|
||||||
|
DrawSquare { x: i32, y: i32, w: i32, h: i32, border_color: Color, fill_color: Color },
|
||||||
|
DrawText { x: i32, y: i32, text: String, color: Color },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct DeferredGfxOverlay {
|
||||||
|
commands: Vec<OverlayCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeferredGfxOverlay {
|
||||||
|
pub fn begin_frame(&mut self) {
|
||||||
|
self.commands.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, command: OverlayCommand) {
|
||||||
|
self.commands.push(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commands(&self) -> &[OverlayCommand] {
|
||||||
|
&self.commands
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command_count(&self) -> usize {
|
||||||
|
self.commands.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -48,6 +48,7 @@ impl Default for Hardware {
|
|||||||
|
|
||||||
impl HardwareBridge for Hardware {
|
impl HardwareBridge for Hardware {
|
||||||
fn begin_frame(&mut self) {
|
fn begin_frame(&mut self) {
|
||||||
|
self.gfx.begin_overlay_frame();
|
||||||
self.frame_composer.begin_frame();
|
self.frame_composer.begin_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ mod asset;
|
|||||||
mod audio;
|
mod audio;
|
||||||
mod frame_composer;
|
mod frame_composer;
|
||||||
mod gfx;
|
mod gfx;
|
||||||
|
mod gfx_overlay;
|
||||||
pub mod hardware;
|
pub mod hardware;
|
||||||
mod memory_banks;
|
mod memory_banks;
|
||||||
mod pad;
|
mod pad;
|
||||||
@ -11,6 +12,7 @@ pub use crate::asset::AssetManager;
|
|||||||
pub use crate::audio::{Audio, AudioCommand, Channel, MAX_CHANNELS, OUTPUT_SAMPLE_RATE};
|
pub use crate::audio::{Audio, AudioCommand, Channel, MAX_CHANNELS, OUTPUT_SAMPLE_RATE};
|
||||||
pub use crate::frame_composer::{FrameComposer, SceneStatus, SpriteController};
|
pub use crate::frame_composer::{FrameComposer, SceneStatus, SpriteController};
|
||||||
pub use crate::gfx::Gfx;
|
pub use crate::gfx::Gfx;
|
||||||
|
pub use crate::gfx_overlay::{DeferredGfxOverlay, OverlayCommand};
|
||||||
pub use crate::memory_banks::{
|
pub use crate::memory_banks::{
|
||||||
GlyphBankPoolAccess, GlyphBankPoolInstaller, MemoryBanks, SceneBankPoolAccess,
|
GlyphBankPoolAccess, GlyphBankPoolInstaller, MemoryBanks, SceneBankPoolAccess,
|
||||||
SceneBankPoolInstaller, SoundBankPoolAccess, SoundBankPoolInstaller,
|
SceneBankPoolInstaller, SoundBankPoolAccess, SoundBankPoolInstaller,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user