use std::{
cell::RefCell,
mem,
os::raw::{c_float, c_int, c_void},
ptr::{self, null_mut},
};
use prelude::*;
use universe::Universe2D;
use util::ColorCalculator;
pub mod driver;
#[allow(non_camel_case_types)]
type em_callback_func = unsafe extern "C" fn();
extern "C" {
pub fn emscripten_set_main_loop(
func: em_callback_func,
fps: c_int,
simulate_infinite_loop: c_int,
);
pub fn emscripten_cancel_main_loop();
pub fn emscripten_get_now() -> c_float;
}
thread_local!(static MAIN_LOOP_CALLBACK: RefCell<*mut c_void> = RefCell::new(null_mut()));
#[allow(clippy::boxed_local)]
pub fn set_main_loop_callback<F>(callback: Box<F>)
where
F: FnMut(),
{
MAIN_LOOP_CALLBACK.with(|log| {
*log.borrow_mut() = Box::into_raw(callback) as *mut c_void;
});
unsafe {
emscripten_set_main_loop(wrapper::<F>, 0, 1);
}
unsafe extern "C" fn wrapper<F>()
where
F: FnMut(),
{
MAIN_LOOP_CALLBACK.with(|z| {
let closure = *z.borrow_mut() as *mut F;
(*closure)();
});
}
}
pub struct EmscriptenDriver;
impl<
C: CellState,
E: EntityState<C>,
M: MutEntityState,
CA: CellAction<C>,
EA: EntityAction<C, E>,
U: Universe<C, E, M>,
N: Engine<C, E, M, CA, EA, U>,
> Driver<C, E, M, CA, EA, U, N> for EmscriptenDriver
{
fn init(
self,
mut universe: U,
mut engine: N,
mut middleware: Vec<Box<Middleware<C, E, M, CA, EA, U, N>>>,
) {
let closure = move || {
println!("In closure...");
for m in middleware.iter_mut() {
m.before_render(&mut universe);
}
engine.step(&mut universe);
for m in middleware.iter_mut() {
m.after_render(&mut universe);
}
};
set_main_loop_callback(Box::new(closure));
}
}
pub struct CanvasRenderer<C: CellState, E: EntityState<C>, M: MutEntityState> {
pixbuf: Vec<u8>,
get_color: ColorCalculator<C, E, M>,
canvas_render: fn(colors: &[u8]),
}
impl<
C: CellState,
E: EntityState<C>,
M: MutEntityState,
CA: CellAction<C>,
EA: EntityAction<C, E>,
N: Engine<C, E, M, CA, EA, Universe2D<C, E, M>>,
> Middleware<C, E, M, CA, EA, Universe2D<C, E, M>, N> for CanvasRenderer<C, E, M>
{
fn after_render(&mut self, universe: &mut Universe2D<C, E, M>) {
let universe_len = universe.cells.len();
let expected_pixbuf_size = universe_len * 4;
if expected_pixbuf_size != self.pixbuf.len() && expected_pixbuf_size != 0 {
self.pixbuf.resize(expected_pixbuf_size, 255u8);
}
for universe_index in 0..universe.cells.len() {
let entities = universe.entities.get_entities_at(universe_index);
let dst_ptr =
unsafe { self.pixbuf.as_ptr().offset(universe_index as isize * 4) } as *mut u32;
unsafe {
ptr::write(
dst_ptr,
mem::transmute::<[u8; 4], _>((self.get_color)(
&universe.cells.get_unchecked(universe_index),
entities,
&universe.entities,
)),
)
};
}
(self.canvas_render)(&self.pixbuf)
}
}
impl<C: CellState, E: EntityState<C>, M: MutEntityState> CanvasRenderer<C, E, M> {
pub fn new(
universe_size: usize,
get_color: ColorCalculator<C, E, M>,
canvas_render: fn(colors: &[u8]),
) -> Self {
CanvasRenderer {
pixbuf: vec![255u8; universe_size * universe_size * 4],
get_color,
canvas_render,
}
}
}
pub enum KeyPress {
Character(char),
Enter,
Other(u8),
}
pub enum UserEvent {
CanvasClick { x: u32, y: u32 },
KeyPress,
Custom(Vec<u8>),
}