use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use deno_core::OpState;
use crate::renderer::SpriteCommand;
use crate::scripting::render_ops::RenderBridgeState;
pub struct TargetState {
pub active_target: Option<u32>,
pub create_queue: Vec<(u32, u32, u32)>, pub destroy_queue: Vec<u32>,
pub target_sprite_queues: HashMap<u32, Vec<SpriteCommand>>,
}
impl TargetState {
pub fn new() -> Self {
Self {
active_target: None,
create_queue: Vec::new(),
destroy_queue: Vec::new(),
target_sprite_queues: HashMap::new(),
}
}
}
#[deno_core::op2(fast)]
fn op_create_render_target(state: &mut OpState, w: f64, h: f64) -> u32 {
let id = {
let bridge = state.borrow_mut::<Rc<RefCell<RenderBridgeState>>>();
let mut b = bridge.borrow_mut();
let id = b.next_texture_id;
b.next_texture_id += 1;
id
};
let ts = state.borrow_mut::<Rc<RefCell<TargetState>>>();
ts.borrow_mut()
.create_queue
.push((id, w as u32, h as u32));
id
}
#[deno_core::op2(fast)]
fn op_begin_render_target(state: &mut OpState, id: u32) {
let ts = state.borrow_mut::<Rc<RefCell<TargetState>>>();
ts.borrow_mut().active_target = Some(id);
}
#[deno_core::op2(fast)]
fn op_end_render_target(state: &mut OpState) {
let ts = state.borrow_mut::<Rc<RefCell<TargetState>>>();
ts.borrow_mut().active_target = None;
}
#[deno_core::op2(fast)]
fn op_destroy_render_target(state: &mut OpState, id: u32) {
let ts = state.borrow_mut::<Rc<RefCell<TargetState>>>();
let mut ts = ts.borrow_mut();
ts.destroy_queue.push(id);
ts.target_sprite_queues.remove(&id);
if ts.active_target == Some(id) {
ts.active_target = None;
}
}
deno_core::extension!(
target_ext,
ops = [
op_create_render_target,
op_begin_render_target,
op_end_render_target,
op_destroy_render_target,
],
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_target_state_new() {
let state = TargetState::new();
assert!(state.active_target.is_none());
assert!(state.create_queue.is_empty());
assert!(state.destroy_queue.is_empty());
assert!(state.target_sprite_queues.is_empty());
}
#[test]
fn test_set_active_target() {
let mut state = TargetState::new();
assert!(state.active_target.is_none());
state.active_target = Some(42);
assert_eq!(state.active_target, Some(42));
state.active_target = None;
assert!(state.active_target.is_none());
}
#[test]
fn test_create_queue() {
let mut state = TargetState::new();
state.create_queue.push((1, 256, 256));
state.create_queue.push((2, 128, 128));
assert_eq!(state.create_queue.len(), 2);
assert_eq!(state.create_queue[0], (1, 256, 256));
assert_eq!(state.create_queue[1], (2, 128, 128));
}
#[test]
fn test_destroy_queue() {
let mut state = TargetState::new();
state.destroy_queue.push(5);
state.destroy_queue.push(10);
assert_eq!(state.destroy_queue.len(), 2);
assert!(state.destroy_queue.contains(&5));
assert!(state.destroy_queue.contains(&10));
}
#[test]
fn test_target_sprite_queues() {
let mut state = TargetState::new();
state.target_sprite_queues.insert(1, Vec::new());
state.target_sprite_queues.insert(2, Vec::new());
assert!(state.target_sprite_queues.contains_key(&1));
assert!(state.target_sprite_queues.contains_key(&2));
assert!(!state.target_sprite_queues.contains_key(&3));
state.target_sprite_queues.remove(&1);
assert!(!state.target_sprite_queues.contains_key(&1));
}
#[test]
fn test_destroy_clears_active() {
let mut state = TargetState::new();
state.active_target = Some(5);
state.destroy_queue.push(5);
state.target_sprite_queues.remove(&5);
if state.active_target == Some(5) {
state.active_target = None;
}
assert!(state.active_target.is_none());
}
}