summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs (renamed from src/main.rs)143
1 files changed, 109 insertions, 34 deletions
diff --git a/src/main.rs b/src/lib.rs
index a9af30d..cbac12e 100644
--- a/src/main.rs
+++ b/src/lib.rs
@@ -1,54 +1,114 @@
+use std::rc::Rc;
+
 use pixels::wgpu::Color;
 use pixels::PixelsBuilder;
 use pixels::SurfaceTexture;
+use rand::distributions::Distribution;
 use rand::distributions::Standard;
-use rand::prelude::Distribution;
-use winit::dpi::PhysicalSize;
+use wasm_bindgen::prelude::*;
+use winit::dpi::LogicalSize;
 use winit::event::Event;
 use winit::event_loop::EventLoop;
 use winit::window::WindowBuilder;
 use winit_input_helper::WinitInputHelper;
 
-const RES_X: usize = 265;
-const RES_Y: usize = 265;
+// const WIDTH: usize = 256;
+// const HEIGHT: usize = 256;
 
-const WIN_WIDTH: u32 = 4 * RES_X as u32;
-const WIN_HEIGHT: u32 = 4 * RES_Y as u32;
+#[wasm_bindgen(start)]
+async fn start() -> Result<(), JsValue> {
+    return run().await.map_err(|err| JsValue::from(err.to_string()));
+}
 
-fn main() -> anyhow::Result<()> {
+async fn run() -> anyhow::Result<()> {
     let event_loop = EventLoop::new();
+
+    // let size = LogicalSize {
+    //     width: WIDTH as f64,
+    //     height: HEIGHT as f64,
+    // };
+
     let window = WindowBuilder::new()
-        .with_inner_size(PhysicalSize {
-            width: WIN_WIDTH,
-            height: WIN_HEIGHT,
-        })
-        .with_resizable(false)
+        // .with_inner_size(size)
+        // .with_min_inner_size(size)
         .build(&event_loop)?;
+
+    let window = Rc::new(window);
+
+    #[cfg(target_arch = "wasm32")]
+    {
+        use winit::platform::web::WindowExtWebSys;
+
+        // Retrieve current width and height dimensions of browser client window
+        let get_window_size = || {
+            let client_window = web_sys::window().unwrap();
+            LogicalSize::new(
+                client_window.inner_width().unwrap().as_f64().unwrap(),
+                client_window.inner_height().unwrap().as_f64().unwrap(),
+            )
+        };
+
+        let window = Rc::clone(&window);
+
+        // Initialize winit window with current dimensions of browser client
+        window.set_inner_size(get_window_size());
+
+        let client_window = web_sys::window().unwrap();
+
+        // Attach winit canvas to body element
+        web_sys::window()
+            .and_then(|win| win.document())
+            .and_then(|doc| doc.body())
+            .and_then(|body| {
+                body.append_child(&web_sys::Element::from(window.canvas()))
+                    .ok()
+            })
+            .expect("couldn't append canvas to document body");
+
+        // Listen for resize event on browser client. Adjust winit window dimensions
+        // on event trigger
+        let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move |_e: web_sys::Event| {
+            let size = get_window_size();
+            window.set_inner_size(size)
+        }) as Box<dyn FnMut(_)>);
+        client_window
+            .add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref())
+            .unwrap();
+        closure.forget();
+    }
+
     let mut input = WinitInputHelper::new();
 
     let window_size = window.inner_size();
-    let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
+    let surface_texture =
+        SurfaceTexture::new(window_size.width, window_size.height, window.as_ref());
+
+    let width = window_size.width / 8;
+    let height = window_size.height / 8;
 
-    let mut pixels = PixelsBuilder::new(RES_X as u32, RES_Y as u32, surface_texture)
+    web_sys::console::log_1(&format!("{} x {}", width, height).into());
+
+    let mut pixels = PixelsBuilder::new(width, height, surface_texture)
         .clear_color(Color {
             r: 0.0,
             g: 0.0,
             b: 0.0,
             a: 1.0,
         })
-        .build()?;
-    let mut life = Life::new();
+        .build_async()
+        .await?;
+    let mut life = Life::new(width as usize, height as usize);
 
     event_loop.run(move |event, _, control_flow| {
         control_flow.set_poll();
 
         if let Event::RedrawRequested(_) = event {
-            life.draw(pixels.get_frame());
+            life.draw(pixels.frame_mut());
             pixels.render().expect("failed to render");
         }
 
         if input.update(&event) {
-            if input.quit() {
+            if input.close_requested() || input.destroyed() {
                 control_flow.set_exit();
                 return;
             };
@@ -67,7 +127,9 @@ enum Cell {
 
 #[derive(Debug)]
 struct Grid {
-    pub cells: [[Cell; RES_X]; RES_Y],
+    pub width: usize,
+    pub height: usize,
+    pub cells: Vec<Vec<Cell>>,
 }
 
 enum FrontGrid {
@@ -76,6 +138,8 @@ enum FrontGrid {
 }
 
 struct Life {
+    pub width: usize,
+    pub height: usize,
     grid_a: Grid,
     grid_b: Grid,
     front_grid: FrontGrid,
@@ -91,26 +155,30 @@ impl Cell {
 }
 
 impl Grid {
-    pub fn blank() -> Self {
+    pub fn blank(width: usize, height: usize) -> Self {
         Self {
-            cells: [[Cell::Dead { since: 0xff }; RES_X]; RES_Y],
+            width,
+            height,
+            cells: vec![vec![Cell::Dead { since: 0xff }; width]; height],
         }
     }
 
-    pub fn with_random_borders() -> Self {
-        let mut ret = Self::blank();
+    pub fn with_random_borders(width: usize, height: usize) -> Self {
+        let mut ret = Self::blank(width, height);
         ret.randomize_border();
         ret
     }
 
     pub fn randomize_border(&mut self) {
-        self.cells[RES_X - 1] = rand::random();
+        for col in 0..self.width {
+            self.cells[self.height - 1][col] = rand::random();
+        }
     }
 
     pub fn draw(&self, frame: &mut [u8]) {
-        for row in 0..RES_X {
-            for col in 0..RES_Y {
-                let pixel_idx = 4 * (RES_X * row + col);
+        for row in 0..self.height {
+            for col in 0..self.width {
+                let pixel_idx = 4 * (self.width * row + col);
 
                 match self.cells[row][col] {
                     Cell::Alive => {
@@ -138,8 +206,8 @@ impl Grid {
     pub fn num_alive_neighbors(&self, row: usize, col: usize) -> u8 {
         let mut ret = 0;
 
-        for i in row.saturating_sub(1)..=(row + 1).min(RES_X - 1) {
-            for j in col.saturating_sub(1)..=(col + 1).min(RES_Y - 1) {
+        for i in row.saturating_sub(1)..=(row + 1).min(self.height - 1) {
+            for j in col.saturating_sub(1)..=(col + 1).min(self.width - 1) {
                 if self.cells[i][j].is_alive() {
                     ret += 1;
                 }
@@ -175,10 +243,12 @@ impl Grid {
 }
 
 impl Life {
-    pub fn new() -> Self {
+    pub fn new(width: usize, height: usize) -> Self {
         Life {
-            grid_a: Grid::with_random_borders(),
-            grid_b: Grid::blank(),
+            width,
+            height,
+            grid_a: Grid::with_random_borders(width, height),
+            grid_b: Grid::blank(width, height),
             front_grid: FrontGrid::A,
         }
     }
@@ -188,10 +258,11 @@ impl Life {
     }
 
     pub fn update(&mut self) {
+        let (width, height) = self.dimensions();
         let (front, back) = self.grids();
 
-        for row in 0..RES_X {
-            for col in 0..RES_Y {
+        for row in 0..height {
+            for col in 0..width {
                 back.cells[row][col] = front.new_state(row, col);
             }
         }
@@ -200,6 +271,10 @@ impl Life {
         self.swap_grids();
     }
 
+    fn dimensions(&self) -> (usize, usize) {
+        (self.width, self.height)
+    }
+
     fn grids(&mut self) -> (&Grid, &mut Grid) {
         match self.front_grid {
             FrontGrid::A => (&self.grid_a, &mut self.grid_b),