moon_engine/
lib.rs

1#![warn(missing_docs)]
2#![warn(rustdoc::missing_doc_code_examples)]
3
4//! Moon Engine
5
6pub mod camera;
7pub mod collider;
8pub mod component;
9pub mod gl;
10pub mod input;
11pub mod math;
12pub mod mesh;
13pub mod particle;
14pub mod renderer;
15pub mod shader;
16pub mod texture;
17pub mod transform;
18pub mod ui;
19pub mod utils;
20pub mod web;
21
22use wasm_bindgen::prelude::*;
23
24use camera::Camera;
25use gl::GL;
26use input::InputManager;
27pub use math::*;
28use particle::ParticleSystem;
29use renderer::Renderer;
30use shader::Shader;
31use texture::Texture;
32use transform::Transform;
33use utils::set_panic_hook;
34use web::Canvas;
35
36// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
37// allocator.
38#[cfg(feature = "wee_alloc")]
39#[global_allocator]
40static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
41
42/// The [`Application`] struct acts as the communicator between the browser and the game logic. It consists of calls made from JavaScript.
43#[wasm_bindgen]
44pub struct Application {
45    renderer: Renderer,
46    input: InputManager,
47}
48
49impl Default for Application {
50    fn default() -> Self {
51        // Initialize the JS panic hook
52        set_panic_hook();
53        Self {
54            renderer: Renderer::default(),
55            input: InputManager::new(),
56        }
57    }
58}
59
60#[allow(clippy::unused_unit)]
61#[wasm_bindgen]
62impl Application {
63    /// Initilize a default [`Application`].
64    #[wasm_bindgen(constructor)]
65    pub fn new() -> Self {
66        Self::default()
67    }
68
69    /// Set up data before render loop.
70    #[wasm_bindgen]
71    pub fn init(&mut self) {
72        let renderer = &mut self.renderer;
73
74        renderer
75            .gl
76            .blend_func(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);
77        renderer.gl.enable(GL::BLEND);
78        // Initialize the default Shader
79        renderer.init_shader();
80
81        let u_tex0 = renderer.program.get_uniform_location(&renderer.gl, "uTex0");
82        renderer.gl.uniform1i(u_tex0.as_ref(), 0);
83
84        renderer.add_texture("TILEMAP", Texture::new_with_texture_id(&renderer.gl, 0));
85        renderer.add_texture("SHREK", Texture::new_with_texture_id(&renderer.gl, 1));
86
87        renderer.use_texture("WHITE");
88
89        let simple = ParticleSystem::new_from_emission_and_position(
90            particle::ParticleProps::default(),
91            0.0,
92            0.0,
93        );
94        renderer.add_component("DEFAULT", Box::new(simple));
95
96        let fire = ParticleSystem::new_from_emission_and_position(
97            particle::ParticleProps::fire(),
98            -5.0,
99            0.0,
100        );
101        renderer.add_component("FIRE", Box::new(fire));
102
103        let smoke = ParticleSystem::new_from_emission_and_position(
104            particle::ParticleProps::smoke(),
105            5.0,
106            0.0,
107        );
108        renderer.add_component("SMOKE", Box::new(smoke));
109
110        renderer.init_components();
111    }
112
113    /// Called when window gets resized.
114    #[wasm_bindgen]
115    pub fn resize(&mut self, width: f32, height: f32) {
116        self.renderer.resize(width, height);
117    }
118
119    /// Called when a keyboard input event is generated.
120    #[wasm_bindgen]
121    pub fn input(&mut self, key_code: u8, is_down: bool) {
122        if is_down {
123            self.input.key_down(key_code);
124        } else {
125            self.input.key_up(key_code);
126        }
127    }
128
129    /// Handles Mouse movement.
130    #[wasm_bindgen]
131    pub fn mouse_move(&mut self, mouse_x: i32, mouse_y: i32) {
132        let (x, y) = self
133            .renderer
134            .camera
135            .screen_to_world_coordinates(mouse_x as f32, mouse_y as f32);
136        self.input.mouse_position = Vec2::new(x, y);
137    }
138
139    /// Renders a new frame.
140    ///
141    /// Called every frame, and draws its output onto the [Canvas](web_sys::HtmlCanvasElement).
142    #[wasm_bindgen]
143    pub fn render(&mut self, delta_time: u32) {
144        let renderer = &mut self.renderer;
145        let delta_time = delta_time as f32 / 1000.0;
146
147        renderer.clear([0.5, 0.2, 0.3, 1.0]);
148
149        if self.input.get_key_state(b'R') {
150            renderer.init_components();
151        }
152        if self.input.get_key_state(b'1') {
153            renderer
154                .get_mut_component::<ParticleSystem>("FIRE")
155                .unwrap()
156                .toggle_alive();
157        }
158        if self.input.get_key_state(b'2') {
159            renderer
160                .get_mut_component::<ParticleSystem>("DEFAULT")
161                .unwrap()
162                .toggle_alive();
163        }
164        if self.input.get_key_state(b'3') {
165            renderer
166                .get_mut_component::<ParticleSystem>("SMOKE")
167                .unwrap()
168                .toggle_alive();
169        }
170        let horizontal =
171            self.input.get_key_state(b'D') as i32 - self.input.get_key_state(b'A') as i32;
172        let vertical =
173            self.input.get_key_state(b'S') as i32 - self.input.get_key_state(b'W') as i32;
174
175        let simple = renderer
176            .get_mut_component::<ParticleSystem>("DEFAULT")
177            .unwrap();
178
179        simple.transform.position = self.input.mouse_position;
180
181        let smoke = renderer
182            .get_mut_component::<ParticleSystem>("SMOKE")
183            .unwrap();
184
185        if smoke.alive {
186            smoke.transform.position +=
187                Vec2::new(horizontal as f32 * delta_time, vertical as f32 * delta_time);
188        }
189
190        renderer.update_components(delta_time);
191
192        renderer.draw_components();
193
194        // self.renderer.begin_layer();
195        // self.renderer.add_quad(Quad::default());
196        // self.renderer.use_texture("MAGENTA");
197        // self.renderer.draw_layer();
198        // self.renderer.delete_layer();
199    }
200}