use crate::{
context::Context,
render::{
buffer::Buffer,
sprite::{Sprite, Layer},
},
util::{
objpool::{GObj, GameObjPool, GameObject},
Rect,
},
LOGO_FRAME,
};
use log::info;
use std::{collections::HashMap, io};
use std::cmp::Reverse;
pub struct Scene {
pub tui_buffers: [Buffer; 2],
pub current: usize,
pub layer_tag_index: HashMap<String, usize>,
pub layers: Vec<Layer>,
pub render_index: Vec<(usize, i32)>,
}
#[allow(unused)]
impl Default for Scene {
fn default() -> Self {
Self::new()
}
}
impl Scene {
#[allow(unused_mut)]
pub fn new() -> Self {
let (width, height) = (180, 80);
let size = Rect::new(0, 0, width, height);
let mut layers = vec![];
let mut layer_tag_index = HashMap::new();
let sprite_layer = Layer::new("sprite");
layers.push(sprite_layer);
layer_tag_index.insert("sprite".to_string(), 0);
Scene {
tui_buffers: [Buffer::empty(size), Buffer::empty(size)],
current: 0,
layer_tag_index,
layers,
render_index: vec![],
}
}
pub fn init(&mut self, ctx: &mut Context) {
#[cfg(target_arch = "wasm32")]
web_sys::console::log_1(&"[scene.init] getting adapter size...".into());
let size = ctx.adapter.size();
#[cfg(target_arch = "wasm32")]
web_sys::console::log_1(&format!("[scene.init] size={:?}, resizing buffers...", size).into());
self.tui_buffers[0].resize(size);
self.tui_buffers[1].resize(size);
info!("scene init size...{:?}", size);
#[cfg(target_arch = "wasm32")]
web_sys::console::log_1(&"[scene.init] done".into());
}
pub fn tui_buffer_mut(&mut self) -> &mut Buffer {
&mut self.tui_buffers[self.current]
}
pub fn current_buffer_mut(&mut self) -> &mut Buffer {
&mut self.tui_buffers[self.current]
}
pub fn add_layer(&mut self, name: &str) {
let layer = Layer::new(name);
self.layers.push(layer);
self.layer_tag_index
.insert(name.to_string(), self.layers.len() - 1);
}
pub fn add_layer_sprite(&mut self, sp: Sprite, layer_name: &str, tag: &str) {
let idx = self.layer_tag_index.get(layer_name).unwrap();
self.layers[*idx].add(sp, tag);
}
pub fn get_layer_sprite(&mut self, layer_name: &str, tag: &str) -> &mut Sprite {
let idx = self.layer_tag_index.get(layer_name).unwrap();
self.layers[*idx].get(tag)
}
pub fn set_layer_weight(&mut self, layer_name: &str, w: i32) {
let idx = self.layer_tag_index.get(layer_name).unwrap();
self.layers[*idx].render_weight = w;
self.render_index.clear();
}
pub fn deactive_layer(&mut self, layer_name: &str) {
let idx = self.layer_tag_index.get(layer_name).unwrap();
self.layers[*idx].deactive();
}
pub fn active_layer(&mut self, layer_name: &str) {
let idx = self.layer_tag_index.get(layer_name).unwrap();
self.layers[*idx].active();
}
pub fn add_sprite(&mut self, sp: Sprite, tag: &str) {
self.layers[0].add(sp, tag);
}
pub fn get_sprite(&mut self, tag: &str) -> &mut Sprite {
self.layers[0].get(tag)
}
pub fn with_sprites<F, R>(&mut self, tags: &[&str], f: F) -> R
where
F: FnOnce(&mut [&mut Sprite]) -> R,
{
self.layers[0].with_sprites(tags, f)
}
pub fn reset(&mut self, ctx: &mut Context) {
ctx.adapter.reset();
}
pub fn update_render_index(&mut self) {
if self.render_index.is_empty() {
for (i, s) in self.layers.iter().enumerate() {
self.render_index.push((i, s.render_weight));
}
self.render_index.sort_by_key(|d| Reverse(d.1));
}
}
pub fn draw_to_rt(&mut self, ctx: &mut Context) -> io::Result<()> {
if ctx.stage > LOGO_FRAME {
#[cfg(not(graphics_mode))]
{
self.update_render_index();
for idx in &self.render_index {
if !self.layers[idx.0].is_hidden {
self.layers[idx.0]
.render_all_to_buffer(&mut ctx.asset_manager, &mut self.tui_buffers[self.current]);
}
}
}
}
let cb = &self.tui_buffers[self.current];
let pb = &self.tui_buffers[1 - self.current];
ctx.adapter
.draw_all(cb, pb, &mut self.layers, ctx.stage)
.unwrap();
ctx.adapter.hide_cursor().unwrap();
if ctx.stage > LOGO_FRAME {
self.tui_buffers[1 - self.current].reset();
self.current = 1 - self.current;
}
Ok(())
}
pub fn draw(&mut self, ctx: &mut Context) -> io::Result<()> {
self.draw_to_rt(ctx)?;
#[cfg(graphics_mode)]
ctx.adapter.present_default();
Ok(())
}
pub fn creat_objpool_sprites<T, F>(
&mut self,
pool: &GameObjPool<T>,
size_x: u16,
size_y: u16,
mut f: F,
) where
T: GObj,
F: FnMut(&mut Sprite),
{
for i in 0..pool.max_count {
let mut bl = Sprite::new(0, 0, size_x, size_y);
f(&mut bl);
bl.set_hidden(true);
self.add_sprite(bl, &format!("{}{}", &pool.prefix, i));
}
}
pub fn draw_objpool<T, F>(&mut self, os: &mut GameObjPool<T>, mut f: F)
where
T: GObj,
F: FnMut(&mut Sprite, &GameObject<T>),
{
for o in &os.pool {
if !o.active {
if let Some(oid) = os.map.remove(&o.id) {
self.get_sprite(&format!("{}{}", os.prefix, oid))
.set_hidden(true);
}
continue;
}
let psid = match os.map.get(&o.id) {
Some(oid) => *oid,
_ => {
let mut mi = 0;
for i in 0..os.max_count {
let pp = self.get_sprite(&format!("{}{}", os.prefix, i));
if pp.is_hidden() {
mi = i;
break;
}
}
os.map.insert(o.id, mi);
mi
}
};
let pl = self.get_sprite(&format!("{}{}", os.prefix, psid));
pl.set_hidden(false);
f(pl, o);
}
}
}