implements PLN-0015
This commit is contained in:
parent
f7c31592bb
commit
4a5763523b
@ -210,6 +210,9 @@ impl GfxBridge for Gfx {
|
||||
fn render_all(&mut self) {
|
||||
self.render_all()
|
||||
}
|
||||
fn render_scene_from_cache(&mut self, cache: &SceneViewportCache, update: &ResolverUpdate) {
|
||||
self.render_scene_from_cache(cache, update)
|
||||
}
|
||||
fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color) {
|
||||
self.draw_text(x, y, text, color)
|
||||
}
|
||||
@ -545,40 +548,11 @@ impl Gfx {
|
||||
&*self.glyph_banks,
|
||||
);
|
||||
|
||||
// 2. Main layers and prioritized sprites.
|
||||
// Order: Layer 0 -> Sprites 1 -> Layer 1 -> Sprites 2 ...
|
||||
// for i in 0..self.layers.len() {
|
||||
// let bank_id = self.layers[i].bank_id as usize;
|
||||
// if let Some(bank) = self.glyph_banks.glyph_bank_slot(bank_id) {
|
||||
// Self::draw_tile_map(
|
||||
// &mut self.back,
|
||||
// self.w,
|
||||
// self.h,
|
||||
// &self.layers[i].map,
|
||||
// &bank,
|
||||
// self.layers[i].scroll_x,
|
||||
// self.layers[i].scroll_y,
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// // Draw sprites that belong to this depth level
|
||||
// Self::draw_bucket_on_buffer(
|
||||
// &mut self.back,
|
||||
// self.w,
|
||||
// self.h,
|
||||
// &self.priority_buckets[i + 1],
|
||||
// &self.sprites,
|
||||
// &*self.glyph_banks,
|
||||
// );
|
||||
// }
|
||||
|
||||
// 4. Scene Fade: Applies a color blend to the entire world (excluding HUD).
|
||||
// 2. Scene-only fallback path: sprites and fades still work even before a
|
||||
// cache-backed world composition request is issued for the frame.
|
||||
Self::apply_fade_to_buffer(&mut self.back, self.scene_fade_level, self.scene_fade_color);
|
||||
|
||||
// 5. HUD: The fixed interface layer, always drawn on top of the world.
|
||||
// Self::render_hud_with_pool(&mut self.back, self.w, self.h, &self.hud, &*self.glyph_banks);
|
||||
|
||||
// 6. HUD Fade: Independent fade effect for the UI.
|
||||
// 3. HUD Fade: independent from scene fade; HUD composition itself remains external.
|
||||
Self::apply_fade_to_buffer(&mut self.back, self.hud_fade_level, self.hud_fade_color);
|
||||
}
|
||||
|
||||
@ -624,137 +598,6 @@ impl Gfx {
|
||||
Self::apply_fade_to_buffer(&mut self.back, self.hud_fade_level, self.hud_fade_color);
|
||||
}
|
||||
|
||||
// /// Renders a specific game layer.
|
||||
// pub fn render_layer(&mut self, layer_idx: usize) {
|
||||
// if layer_idx >= self.layers.len() {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// let bank_id = self.layers[layer_idx].bank_id as usize;
|
||||
// let scroll_x = self.layers[layer_idx].scroll_x;
|
||||
// let scroll_y = self.layers[layer_idx].scroll_y;
|
||||
//
|
||||
// let bank = match self.glyph_banks.glyph_bank_slot(bank_id) {
|
||||
// Some(b) => b,
|
||||
// _ => return,
|
||||
// };
|
||||
//
|
||||
// Self::draw_tile_map(
|
||||
// &mut self.back,
|
||||
// self.w,
|
||||
// self.h,
|
||||
// &self.layers[layer_idx].map,
|
||||
// &bank,
|
||||
// scroll_x,
|
||||
// scroll_y,
|
||||
// );
|
||||
// }
|
||||
|
||||
// /// Rasterizes a TileMap into the provided pixel buffer using scrolling.
|
||||
// fn draw_tile_map(
|
||||
// back: &mut [u16],
|
||||
// screen_w: usize,
|
||||
// screen_h: usize,
|
||||
// map: &TileMap,
|
||||
// bank: &GlyphBank,
|
||||
// scroll_x: i32,
|
||||
// scroll_y: i32,
|
||||
// ) {
|
||||
// let tile_size = bank.tile_size as usize;
|
||||
//
|
||||
// // 1. Determine the range of visible tiles based on the scroll position.
|
||||
// // We add a margin of 1 tile to ensure smooth pixel-perfect scrolling at the borders.
|
||||
// let visible_tiles_x = (screen_w / tile_size) + 1;
|
||||
// let visible_tiles_y = (screen_h / tile_size) + 1;
|
||||
//
|
||||
// // 2. Calculate offsets within the tilemap.
|
||||
// let start_tile_x = scroll_x / tile_size as i32;
|
||||
// let start_tile_y = scroll_y / tile_size as i32;
|
||||
//
|
||||
// // 3. Fine scroll: how many pixels the tiles are shifted within the first visible cell.
|
||||
// let fine_scroll_x = scroll_x % tile_size as i32;
|
||||
// let fine_scroll_y = scroll_y % tile_size as i32;
|
||||
//
|
||||
// // 4. Iterate only through the tiles that are actually visible on screen.
|
||||
// for ty in 0..visible_tiles_y {
|
||||
// for tx in 0..visible_tiles_x {
|
||||
// let map_x = (start_tile_x + tx as i32) as usize;
|
||||
// let map_y = (start_tile_y + ty as i32) as usize;
|
||||
//
|
||||
// // Bounds check: don't draw if the camera is outside the map.
|
||||
// if map_x >= map.width || map_y >= map.height {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// let tile = map.tiles[map_y * map.width + map_x];
|
||||
//
|
||||
// // Optimized skip for empty (ID 0) tiles.
|
||||
// if !tile.active {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // 5. Project the tile pixels to screen space.
|
||||
// let screen_tile_x = (tx as i32 * tile_size as i32) - fine_scroll_x;
|
||||
// let screen_tile_y = (ty as i32 * tile_size as i32) - fine_scroll_y;
|
||||
//
|
||||
// Self::draw_tile_pixels(
|
||||
// back,
|
||||
// screen_w,
|
||||
// screen_h,
|
||||
// screen_tile_x,
|
||||
// screen_tile_y,
|
||||
// tile,
|
||||
// bank,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Internal helper to copy a single tile's pixels to the framebuffer.
|
||||
// /// Handles flipping and palette resolution.
|
||||
// fn draw_tile_pixels(
|
||||
// back: &mut [u16],
|
||||
// screen_w: usize,
|
||||
// screen_h: usize,
|
||||
// x: i32,
|
||||
// y: i32,
|
||||
// tile: Tile,
|
||||
// bank: &GlyphBank,
|
||||
// ) {
|
||||
// let size = bank.tile_size as usize;
|
||||
//
|
||||
// for local_y in 0..size {
|
||||
// let world_y = y + local_y as i32;
|
||||
// if world_y < 0 || world_y >= screen_h as i32 {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// for local_x in 0..size {
|
||||
// let world_x = x + local_x as i32;
|
||||
// if world_x < 0 || world_x >= screen_w as i32 {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // Handle flip flags by reversing the fetch coordinates.
|
||||
// let fetch_x = if tile.flip_x { size - 1 - local_x } else { local_x };
|
||||
// let fetch_y = if tile.flip_y { size - 1 - local_y } else { local_y };
|
||||
//
|
||||
// // 1. Get the pixel color index (0-15) from the bank.
|
||||
// let px_index = bank.get_pixel_index(tile.glyph.glyph_id, fetch_x, fetch_y);
|
||||
//
|
||||
// // 2. Hardware rule: Color index 0 is always fully transparent.
|
||||
// if px_index == 0 {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // 3. Resolve the virtual index to a real RGB565 color using the tile's assigned palette.
|
||||
// let color = bank.resolve_color(tile.glyph.palette_id, px_index);
|
||||
//
|
||||
// back[world_y as usize * screen_w + world_x as usize] = color.raw();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fn populate_priority_buckets(&mut self) {
|
||||
for bucket in self.priority_buckets.iter_mut() {
|
||||
bucket.clear();
|
||||
|
||||
@ -87,7 +87,11 @@ impl Hardware {
|
||||
|
||||
/// Creates a fresh hardware instance with default settings.
|
||||
pub fn new() -> Self {
|
||||
let memory_banks = Arc::new(MemoryBanks::new());
|
||||
Self::new_with_memory_banks(Arc::new(MemoryBanks::new()))
|
||||
}
|
||||
|
||||
/// Creates hardware with explicit shared bank ownership.
|
||||
pub fn new_with_memory_banks(memory_banks: Arc<MemoryBanks>) -> Self {
|
||||
Self {
|
||||
gfx: Gfx::new(
|
||||
Self::W,
|
||||
@ -107,3 +111,75 @@ impl Hardware {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::memory_banks::{
|
||||
GlyphBankPoolInstaller, SceneBankPoolAccess, SceneBankPoolInstaller,
|
||||
};
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
use prometeu_hal::glyph_bank::{GlyphBank, TileSize};
|
||||
use prometeu_hal::scene_bank::SceneBank;
|
||||
use prometeu_hal::scene_layer::{MotionFactor, SceneLayer};
|
||||
use prometeu_hal::scene_viewport_cache::SceneViewportCache;
|
||||
use prometeu_hal::scene_viewport_resolver::SceneViewportResolver;
|
||||
use prometeu_hal::tile::Tile;
|
||||
use prometeu_hal::tilemap::TileMap;
|
||||
|
||||
fn make_glyph_bank() -> GlyphBank {
|
||||
let mut bank = GlyphBank::new(TileSize::Size8, 8, 8);
|
||||
bank.palettes[0][1] = Color::RED;
|
||||
for pixel in &mut bank.pixel_indices {
|
||||
*pixel = 1;
|
||||
}
|
||||
bank
|
||||
}
|
||||
|
||||
fn make_scene() -> SceneBank {
|
||||
let layer = SceneLayer {
|
||||
active: true,
|
||||
glyph_bank_id: 0,
|
||||
tile_size: TileSize::Size8,
|
||||
motion_factor: MotionFactor { x: 1.0, y: 1.0 },
|
||||
tilemap: TileMap {
|
||||
width: 4,
|
||||
height: 4,
|
||||
tiles: vec![
|
||||
Tile {
|
||||
active: true,
|
||||
glyph: Glyph { glyph_id: 0, palette_id: 0 },
|
||||
flip_x: false,
|
||||
flip_y: false,
|
||||
};
|
||||
16
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
SceneBank { layers: std::array::from_fn(|_| layer.clone()) }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hardware_can_render_scene_from_shared_scene_bank_pipeline() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
banks.install_glyph_bank(0, Arc::new(make_glyph_bank()));
|
||||
banks.install_scene_bank(0, Arc::new(make_scene()));
|
||||
|
||||
let mut hardware = Hardware::new_with_memory_banks(Arc::clone(&banks));
|
||||
let scene = banks.scene_bank_slot(0).expect("scene bank slot 0 should be resident");
|
||||
let mut cache = SceneViewportCache::new(&scene, 4, 4);
|
||||
cache.materialize_all_layers(&scene);
|
||||
|
||||
let mut resolver = SceneViewportResolver::new(16, 16, 4, 4, 12, 20);
|
||||
let update = resolver.update(&scene, 0, 0);
|
||||
|
||||
hardware.gfx.scene_fade_level = 31;
|
||||
hardware.gfx.hud_fade_level = 31;
|
||||
hardware.gfx.render_scene_from_cache(&cache, &update);
|
||||
hardware.gfx.present();
|
||||
|
||||
assert_eq!(hardware.gfx.front_buffer()[0], Color::RED.raw());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,5 +9,8 @@ mod touch;
|
||||
pub use crate::asset::AssetManager;
|
||||
pub use crate::audio::{Audio, AudioCommand, Channel, MAX_CHANNELS, OUTPUT_SAMPLE_RATE};
|
||||
pub use crate::gfx::Gfx;
|
||||
pub use crate::memory_banks::MemoryBanks;
|
||||
pub use crate::memory_banks::{
|
||||
GlyphBankPoolAccess, GlyphBankPoolInstaller, MemoryBanks, SceneBankPoolAccess,
|
||||
SceneBankPoolInstaller, SoundBankPoolAccess, SoundBankPoolInstaller,
|
||||
};
|
||||
pub use crate::pad::Pad;
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
use crate::color::Color;
|
||||
use crate::scene_viewport_cache::SceneViewportCache;
|
||||
use crate::scene_viewport_resolver::ResolverUpdate;
|
||||
use crate::sprite::Sprite;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -47,6 +49,7 @@ pub trait GfxBridge {
|
||||
fn draw_vertical_line(&mut self, x: i32, y0: i32, y1: i32, color: Color);
|
||||
fn present(&mut self);
|
||||
fn render_all(&mut self);
|
||||
fn render_scene_from_cache(&mut self, cache: &SceneViewportCache, update: &ResolverUpdate);
|
||||
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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user