implements PLN-0020
This commit is contained in:
parent
3931e86b41
commit
5ef43045bc
@ -1,8 +1,9 @@
|
||||
use crate::memory_banks::SceneBankPoolAccess;
|
||||
use prometeu_hal::GfxBridge;
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
use prometeu_hal::scene_bank::SceneBank;
|
||||
use prometeu_hal::scene_viewport_cache::SceneViewportCache;
|
||||
use prometeu_hal::scene_viewport_resolver::SceneViewportResolver;
|
||||
use prometeu_hal::scene_viewport_resolver::{CacheRefreshRequest, SceneViewportResolver};
|
||||
use prometeu_hal::sprite::Sprite;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -22,7 +23,9 @@ const EMPTY_SPRITE: Sprite = Sprite {
|
||||
pub enum SceneStatus {
|
||||
#[default]
|
||||
Unbound,
|
||||
Available { scene_bank_id: usize },
|
||||
Available {
|
||||
scene_bank_id: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -235,6 +238,22 @@ impl FrameComposer {
|
||||
self.sprite_controller.ordered_sprites()
|
||||
}
|
||||
|
||||
pub fn render_frame(&mut self, gfx: &mut dyn GfxBridge) {
|
||||
let ordered_sprites = self.ordered_sprites();
|
||||
gfx.load_frame_sprites(&ordered_sprites);
|
||||
|
||||
if let (Some(scene), Some(cache), Some(resolver)) =
|
||||
(self.active_scene.as_deref(), self.cache.as_mut(), self.resolver.as_mut())
|
||||
{
|
||||
let update = resolver.update(scene, self.camera_x_px, self.camera_y_px);
|
||||
Self::apply_refresh_requests(cache, scene, &update.refresh_requests);
|
||||
gfx.render_scene_from_cache(cache, &update);
|
||||
return;
|
||||
}
|
||||
|
||||
gfx.render_all();
|
||||
}
|
||||
|
||||
fn build_scene_runtime(
|
||||
viewport_width_px: usize,
|
||||
viewport_height_px: usize,
|
||||
@ -259,22 +278,57 @@ impl FrameComposer {
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn apply_refresh_requests(
|
||||
cache: &mut SceneViewportCache,
|
||||
scene: &SceneBank,
|
||||
refresh_requests: &[CacheRefreshRequest],
|
||||
) {
|
||||
for request in refresh_requests {
|
||||
match *request {
|
||||
CacheRefreshRequest::InvalidateLayer { layer_index } => {
|
||||
cache.layers[layer_index].invalidate_all();
|
||||
}
|
||||
CacheRefreshRequest::RefreshLine { layer_index, cache_y } => {
|
||||
cache.refresh_layer_line(scene, layer_index, cache_y);
|
||||
}
|
||||
CacheRefreshRequest::RefreshColumn { layer_index, cache_x } => {
|
||||
cache.refresh_layer_column(scene, layer_index, cache_x);
|
||||
}
|
||||
CacheRefreshRequest::RefreshRegion { layer_index, region } => {
|
||||
cache.refresh_layer_region(scene, layer_index, region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::memory_banks::{MemoryBanks, SceneBankPoolInstaller};
|
||||
use prometeu_hal::glyph_bank::TileSize;
|
||||
use crate::gfx::Gfx;
|
||||
use crate::memory_banks::{
|
||||
GlyphBankPoolAccess, GlyphBankPoolInstaller, MemoryBanks, SceneBankPoolInstaller,
|
||||
};
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::glyph_bank::{GlyphBank, TileSize};
|
||||
use prometeu_hal::scene_layer::{ParallaxFactor, SceneLayer};
|
||||
use prometeu_hal::tile::Tile;
|
||||
use prometeu_hal::tilemap::TileMap;
|
||||
|
||||
fn make_scene() -> SceneBank {
|
||||
make_scene_with_palette(1, 1, TileSize::Size8)
|
||||
}
|
||||
|
||||
fn make_scene_with_palette(
|
||||
glyph_bank_id: u8,
|
||||
palette_id: u8,
|
||||
tile_size: TileSize,
|
||||
) -> SceneBank {
|
||||
let layer = SceneLayer {
|
||||
active: true,
|
||||
glyph_bank_id: 1,
|
||||
tile_size: TileSize::Size8,
|
||||
glyph_bank_id,
|
||||
tile_size,
|
||||
parallax_factor: ParallaxFactor { x: 1.0, y: 0.5 },
|
||||
tilemap: TileMap {
|
||||
width: 2,
|
||||
@ -282,7 +336,7 @@ mod tests {
|
||||
tiles: vec![
|
||||
Tile {
|
||||
active: true,
|
||||
glyph: Glyph { glyph_id: 9, palette_id: 1 },
|
||||
glyph: Glyph { glyph_id: 0, palette_id },
|
||||
flip_x: false,
|
||||
flip_y: false,
|
||||
};
|
||||
@ -294,6 +348,16 @@ mod tests {
|
||||
SceneBank { layers: std::array::from_fn(|_| layer.clone()) }
|
||||
}
|
||||
|
||||
fn make_glyph_bank(tile_size: TileSize, palette_id: u8, color: Color) -> GlyphBank {
|
||||
let size = tile_size as usize;
|
||||
let mut bank = GlyphBank::new(tile_size, size, size);
|
||||
bank.palettes[palette_id as usize][1] = color;
|
||||
for pixel in &mut bank.pixel_indices {
|
||||
*pixel = 1;
|
||||
}
|
||||
bank
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frame_composer_starts_unbound_with_empty_owned_state() {
|
||||
let frame_composer = FrameComposer::new(320, 180, Arc::new(MemoryBanks::new()));
|
||||
@ -329,7 +393,8 @@ mod tests {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
banks.install_scene_bank(3, Arc::new(make_scene()));
|
||||
|
||||
let expected_scene = banks.scene_bank_slot(3).expect("scene bank slot 3 should be resident");
|
||||
let expected_scene =
|
||||
banks.scene_bank_slot(3).expect("scene bank slot 3 should be resident");
|
||||
let mut frame_composer = FrameComposer::new(320, 180, banks);
|
||||
|
||||
assert!(frame_composer.bind_scene(3));
|
||||
@ -544,4 +609,106 @@ mod tests {
|
||||
assert_eq!(ordered[0].glyph.glyph_id, 20);
|
||||
assert_eq!(ordered[1].glyph.glyph_id, 21);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_frame_without_scene_uses_sprite_only_path() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
banks.install_glyph_bank(1, Arc::new(make_glyph_bank(TileSize::Size8, 3, Color::WHITE)));
|
||||
|
||||
let mut frame_composer =
|
||||
FrameComposer::new(16, 16, Arc::clone(&banks) as Arc<dyn SceneBankPoolAccess>);
|
||||
frame_composer.begin_frame();
|
||||
assert!(frame_composer.emit_sprite(Sprite {
|
||||
glyph: Glyph { glyph_id: 0, palette_id: 3 },
|
||||
x: 0,
|
||||
y: 0,
|
||||
layer: 0,
|
||||
bank_id: 1,
|
||||
active: false,
|
||||
flip_x: false,
|
||||
flip_y: false,
|
||||
priority: 0,
|
||||
}));
|
||||
|
||||
let mut gfx = Gfx::new(16, 16, Arc::clone(&banks) as Arc<dyn GlyphBankPoolAccess>);
|
||||
gfx.scene_fade_level = 31;
|
||||
gfx.hud_fade_level = 31;
|
||||
|
||||
frame_composer.render_frame(&mut gfx);
|
||||
gfx.present();
|
||||
|
||||
assert_eq!(gfx.front_buffer()[0], Color::WHITE.raw());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_frame_with_scene_applies_refreshes_before_composition() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
banks.install_glyph_bank(0, Arc::new(make_glyph_bank(TileSize::Size8, 2, Color::BLUE)));
|
||||
banks.install_scene_bank(0, Arc::new(make_scene_with_palette(0, 2, TileSize::Size8)));
|
||||
|
||||
let mut frame_composer =
|
||||
FrameComposer::new(16, 16, Arc::clone(&banks) as Arc<dyn SceneBankPoolAccess>);
|
||||
assert!(frame_composer.bind_scene(0));
|
||||
|
||||
let mut gfx = Gfx::new(16, 16, Arc::clone(&banks) as Arc<dyn GlyphBankPoolAccess>);
|
||||
gfx.scene_fade_level = 31;
|
||||
gfx.hud_fade_level = 31;
|
||||
|
||||
frame_composer.render_frame(&mut gfx);
|
||||
gfx.present();
|
||||
|
||||
assert!(
|
||||
frame_composer
|
||||
.cache()
|
||||
.expect("cache should exist")
|
||||
.layers
|
||||
.iter()
|
||||
.all(|layer| layer.valid)
|
||||
);
|
||||
assert_eq!(gfx.front_buffer()[0], Color::BLUE.raw());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_frame_survives_scene_transition_through_unbind_and_rebind() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
banks.install_glyph_bank(0, Arc::new(make_glyph_bank(TileSize::Size8, 1, Color::RED)));
|
||||
banks.install_glyph_bank(1, Arc::new(make_glyph_bank(TileSize::Size8, 2, Color::BLUE)));
|
||||
banks.install_glyph_bank(2, Arc::new(make_glyph_bank(TileSize::Size8, 3, Color::WHITE)));
|
||||
banks.install_scene_bank(0, Arc::new(make_scene_with_palette(0, 1, TileSize::Size8)));
|
||||
banks.install_scene_bank(1, Arc::new(make_scene_with_palette(1, 2, TileSize::Size8)));
|
||||
|
||||
let mut frame_composer =
|
||||
FrameComposer::new(16, 16, Arc::clone(&banks) as Arc<dyn SceneBankPoolAccess>);
|
||||
let mut gfx = Gfx::new(16, 16, Arc::clone(&banks) as Arc<dyn GlyphBankPoolAccess>);
|
||||
gfx.scene_fade_level = 31;
|
||||
gfx.hud_fade_level = 31;
|
||||
|
||||
assert!(frame_composer.bind_scene(0));
|
||||
frame_composer.render_frame(&mut gfx);
|
||||
gfx.present();
|
||||
assert_eq!(gfx.front_buffer()[0], Color::RED.raw());
|
||||
|
||||
frame_composer.unbind_scene();
|
||||
frame_composer.begin_frame();
|
||||
assert!(frame_composer.emit_sprite(Sprite {
|
||||
glyph: Glyph { glyph_id: 0, palette_id: 3 },
|
||||
x: 0,
|
||||
y: 0,
|
||||
layer: 0,
|
||||
bank_id: 2,
|
||||
active: false,
|
||||
flip_x: false,
|
||||
flip_y: false,
|
||||
priority: 0,
|
||||
}));
|
||||
frame_composer.render_frame(&mut gfx);
|
||||
gfx.present();
|
||||
assert_eq!(gfx.front_buffer()[0], Color::WHITE.raw());
|
||||
|
||||
frame_composer.begin_frame();
|
||||
assert!(frame_composer.bind_scene(1));
|
||||
frame_composer.render_frame(&mut gfx);
|
||||
gfx.present();
|
||||
assert_eq!(gfx.front_buffer()[0], Color::BLUE.raw());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user