1use std::collections::BTreeMap;
4use std::fmt;
5use std::rc::Rc;
6use web_sys::WebGlUniformLocation;
7
8use crate::component::Component;
9use crate::{gl, mesh, texture, Color32};
10use crate::{Camera, Shader, Transform, GL};
11
12use gl::Bind;
13use mesh::{Mesh, Vertex};
14use texture::{SubTexture, Texture};
15
16pub const MAX_BATCH_QUADS: i32 = 1000;
18const MAX_BATCH_VERTICES: i32 = MAX_BATCH_QUADS * 4;
19const MAX_BATCH_INDICES: i32 = MAX_BATCH_QUADS * 6;
20
21#[derive(Debug)]
23pub struct Quad([Vertex; 4]);
24
25impl Default for Quad {
26 fn default() -> Self {
27 Self([
28 Vertex {
29 position: [-0.5, 0.5],
30 uv: [0.0, 0.0],
31 ..Default::default()
32 },
33 Vertex {
34 position: [-0.5, -0.5],
35 uv: [0.0, 1.0],
36 ..Default::default()
37 },
38 Vertex {
39 position: [0.5, -0.5],
40 uv: [1.0, 1.0],
41 ..Default::default()
42 },
43 Vertex {
44 position: [0.5, 0.5],
45 uv: [1.0, 0.0],
46 ..Default::default()
47 },
48 ])
49 }
50}
51
52impl Quad {
53 pub fn new_from_position_and_rotation_and_size_and_color(
55 pos_x: f32,
56 pos_y: f32,
57 rotation: f32,
58 size_x: f32,
59 size_y: f32,
60 color: Color32,
61 ) -> Self {
62 let size_x = size_x / 2.0;
63 let size_y = size_y / 2.0;
64 let color = <[f32; 4]>::from(color);
65 let (sin_theta, cos_theta) = rotation.sin_cos();
66 let mut points = [
67 [-size_x, -size_y],
68 [-size_x, size_y],
69 [size_x, size_y],
70 [size_x, -size_y],
71 ];
72 for point in points.iter_mut() {
73 let (x, y) = (point[0], point[1]);
74 point[0] = pos_x + x * cos_theta - y * sin_theta;
75 point[1] = pos_y + x * sin_theta + y * cos_theta;
76 }
77 Self([
78 Vertex {
79 position: points[0],
80 uv: [0.0, 0.0],
81 color,
82 },
83 Vertex {
84 position: points[1],
85 uv: [0.0, 1.0],
86 color,
87 },
88 Vertex {
89 position: points[2],
90 uv: [1.0, 1.0],
91 color,
92 },
93 Vertex {
94 position: points[3],
95 uv: [1.0, 0.0],
96 color,
97 },
98 ])
99 }
100
101 pub fn new_from_position_and_size_and_color(
103 pos_x: f32,
104 pos_y: f32,
105 size_x: f32,
106 size_y: f32,
107 color: Color32,
108 ) -> Self {
109 let size_x = size_x / 2.0;
110 let size_y = size_y / 2.0;
111 let color = <[f32; 4]>::from(color);
112 Self([
113 Vertex {
114 position: [pos_x - size_x, pos_y + size_y],
115 uv: [0.0, 0.0],
116 color,
117 },
118 Vertex {
119 position: [pos_x - size_x, pos_y - size_y],
120 uv: [0.0, 1.0],
121 color,
122 },
123 Vertex {
124 position: [pos_x + size_x, pos_y - size_y],
125 uv: [1.0, 1.0],
126 color,
127 },
128 Vertex {
129 position: [pos_x + size_x, pos_y + size_y],
130 uv: [1.0, 0.0],
131 color,
132 },
133 ])
134 }
135
136 pub fn new_from_position_and_size(pos_x: f32, pos_y: f32, size_x: f32, size_y: f32) -> Self {
138 Self::new_from_position_and_size_and_color(pos_x, pos_y, size_x, size_y, Color32::WHITE)
139 }
140
141 pub fn new_from_position_and_size_and_sprite(
143 pos_x: f32,
144 pos_y: f32,
145 size_x: f32,
146 size_y: f32,
147 sprite: &SubTexture,
148 ) -> Self {
149 let uv = sprite.get_uv_coords();
150 let size_x = size_x / 2.0;
151 let size_y = size_y / 2.0;
152 Self([
153 Vertex {
154 position: [pos_x - size_x, pos_y + size_y],
155 uv: uv[0],
156 ..Default::default()
157 },
158 Vertex {
159 position: [pos_x - size_x, pos_y - size_y],
160 uv: uv[1],
161 ..Default::default()
162 },
163 Vertex {
164 position: [pos_x + size_x, pos_y - size_y],
165 uv: uv[2],
166 ..Default::default()
167 },
168 Vertex {
169 position: [pos_x + size_x, pos_y + size_y],
170 uv: uv[3],
171 ..Default::default()
172 },
173 ])
174 }
175
176 pub fn new_from_transform(transform: Transform) -> Self {
178 Self::new_from_position_and_size(
179 transform.position.x,
180 transform.position.x,
181 transform.scale.x,
182 transform.scale.y,
183 )
184 }
185
186 pub fn new_from_transform_and_sprite(transform: Transform, sprite: &SubTexture) -> Self {
188 Self::new_from_position_and_size_and_sprite(
189 transform.position.x,
190 transform.position.x,
191 transform.scale.x,
192 transform.scale.y,
193 sprite,
194 )
195 }
196
197 pub fn get_vertices(&self) -> Vec<Vertex> {
199 self.0.to_vec()
200 }
201}
202
203pub struct Renderer {
205 pub gl: GL,
207 pub program: Shader,
209 pub camera: Camera,
211 batches: Vec<Mesh>,
212 pub components: BTreeMap<&'static str, Box<dyn Component>>,
214 textures: BTreeMap<&'static str, Rc<Texture>>,
215 u_time: Option<WebGlUniformLocation>,
216 u_color: Option<WebGlUniformLocation>,
217 u_model_matrix: Option<WebGlUniformLocation>,
218 u_view_matrix: Option<WebGlUniformLocation>,
219 u_projection_matrix: Option<WebGlUniformLocation>,
220}
221
222impl Default for Renderer {
223 fn default() -> Self {
224 let gl = gl::get_context();
225 let program = Shader::new(&gl);
226 Self {
227 camera: Camera::default(),
228 batches: Vec::new(),
229 components: BTreeMap::new(),
230 u_time: program.get_uniform_location(&gl, "uTime"),
231 u_color: program.get_uniform_location(&gl, "uColor"),
232 u_model_matrix: program.get_uniform_location(&gl, "uModel"),
233 u_view_matrix: program.get_uniform_location(&gl, "uView"),
234 u_projection_matrix: program.get_uniform_location(&gl, "uProj"),
235 program,
236 textures: {
237 let mut textues = BTreeMap::<&str, Rc<Texture>>::new();
238 textues.insert("WHITE", Rc::new(Texture::white(&gl)));
239 textues.insert("MAGENTA", Rc::new(Texture::colored(&gl, Color32::MAGENTA)));
240 textues.insert("CHECKERBOARD", Rc::new(Texture::checkerboard(&gl)));
241 textues
242 },
243 gl,
244 }
245 }
246}
247
248impl fmt::Debug for Renderer {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 f.debug_struct("Renderer")
251 .field("gl", &self.gl)
252 .field("program", &self.program)
253 .field("camera", &self.camera)
254 .field("batches", &self.batches)
255 .field("textures", &self.textures)
256 .field("u_time", &self.u_time)
257 .field("u_color", &self.u_color)
258 .field("u_model_matrix", &self.u_model_matrix)
259 .field("u_view_matrix", &self.u_view_matrix)
260 .field("u_projection_matrix", &self.u_projection_matrix)
261 .finish()
262 }
263}
264
265impl Renderer {
266 pub fn new_with_camera(camera: Camera) -> Self {
268 Self {
269 camera,
270 ..Default::default()
271 }
272 }
273
274 pub fn new_with_camera_and_program(camera: Camera, program: Shader) -> Self {
276 let gl = gl::get_context();
277 program.bind(&gl);
278
279 Self {
280 camera,
281 u_time: program.get_uniform_location(&gl, "uTime"),
282 u_color: program.get_uniform_location(&gl, "uColor"),
283 u_model_matrix: program.get_uniform_location(&gl, "uModel"),
284 u_view_matrix: program.get_uniform_location(&gl, "uView"),
285 u_projection_matrix: program.get_uniform_location(&gl, "uProj"),
286 program,
287 gl,
288 ..Default::default()
289 }
290 }
291
292 pub fn set_camera(&mut self, camera: Camera) {
294 self.camera = camera;
295 }
296
297 pub fn set_shader(&mut self, program: Shader) {
299 let gl = &self.gl;
300
301 self.u_time = program.get_uniform_location(gl, "uTime");
302 self.u_color = program.get_uniform_location(gl, "uColor");
303 self.u_model_matrix = program.get_uniform_location(gl, "uModel");
304 self.u_view_matrix = program.get_uniform_location(gl, "uView");
305 self.u_projection_matrix = program.get_uniform_location(gl, "uProj");
306 self.program = program;
307 }
308
309 pub fn resize(&mut self, width: f32, height: f32) {
311 self.camera.set_width_and_height(width, height);
312 self.gl.viewport(0, 0, width as i32, height as i32);
313 self.gl.uniform_matrix4fv_with_f32_array(
314 self.u_projection_matrix.as_ref(),
315 false,
316 self.camera.projection(),
317 );
318 }
319
320 pub fn init_shader(&mut self) {
322 let gl = &self.gl;
323 self.program.bind(gl);
324
325 gl.uniform1f(self.u_time.as_ref(), 0.0);
326 gl.uniform4f(self.u_color.as_ref(), 1.0, 1.0, 1.0, 1.0);
327 gl.uniform_matrix4fv_with_f32_array(
328 self.u_view_matrix.as_ref(),
329 false,
330 crate::Mat4::identity().as_slice(),
331 );
332 gl.uniform_matrix4fv_with_f32_array(
333 self.u_view_matrix.as_ref(),
334 false,
335 self.camera.transform.matrix_slice(),
336 );
337 gl.uniform_matrix4fv_with_f32_array(
338 self.u_projection_matrix.as_ref(),
339 false,
340 self.camera.projection(),
341 );
342 }
343
344 pub fn add_texture(&mut self, key: &'static str, texture: Texture) {
348 self.textures.insert(key, Rc::new(texture));
349 }
350
351 pub fn use_texture(&self, key: &str) {
355 let gl = &self.gl;
356 self.textures
357 .get(key)
358 .unwrap_or_else(|| self.textures.get("MAGENTA").unwrap())
359 .bind(gl);
360 }
361
362 pub fn get_texture(&mut self, key: &str) -> Rc<Texture> {
364 Rc::clone(
365 self.textures
366 .get(key)
367 .unwrap_or_else(|| self.textures.get("MAGENTA").unwrap())
368 )
369 }
370
371 pub fn begin_draw(&mut self) {
373 let gl = &self.gl;
374
375 self.batches.clear();
376
377 let mesh = Mesh::new(
378 gl,
379 Vec::with_capacity(MAX_BATCH_VERTICES as usize),
380 Vec::with_capacity(MAX_BATCH_INDICES as usize),
381 );
382
383 self.batches.push(mesh);
384 }
385
386 pub fn add_quad(&mut self, quad: &Quad) {
388 let gl = &self.gl;
389
390 let mut batch = self
392 .batches
393 .last_mut()
394 .expect("Batch list empty. Check if begin_draw was called before.");
395 if batch.vertices.len() + 4 > MAX_BATCH_VERTICES as usize {
396 let mesh = Mesh::new(
397 gl,
398 Vec::with_capacity(MAX_BATCH_VERTICES as usize),
399 Vec::with_capacity(MAX_BATCH_INDICES as usize),
400 );
401 self.batches.push(mesh);
402
403 batch = self.batches.last_mut().unwrap();
404 }
405
406 let last = batch.vertices.len() as u32;
407 batch.vertices.append(&mut quad.get_vertices());
408 let mut indices = vec![last, last + 2, last + 1, last, last + 3, last + 2];
409 batch.indices.append(&mut indices);
410 }
411
412 pub fn begin_layer(&mut self) {
416 let gl = &self.gl;
417 let mesh = Mesh::new(
418 gl,
419 Vec::with_capacity(MAX_BATCH_VERTICES as usize),
420 Vec::with_capacity(MAX_BATCH_INDICES as usize),
421 );
422
423 self.batches.push(mesh);
424 }
425
426 pub fn delete_layer(&mut self) -> Option<Mesh> {
428 self.batches.pop()
429 }
430
431 pub fn draw_layer(&self) {
433 let gl = &self.gl;
434 if let Some(batch) = self.batches.last() {
435 batch.setup(gl);
436 gl.draw_elements_with_i32(
437 GL::TRIANGLES,
438 batch.indices.len() as i32,
439 GL::UNSIGNED_INT,
440 0,
441 );
442 }
443 }
444
445 pub fn end_draw(&mut self) {
447 let gl = &self.gl;
448 gl.uniform_matrix4fv_with_f32_array(
449 self.u_view_matrix.as_ref(),
450 false,
451 self.camera.transform.matrix_slice(),
452 );
453 self.program.bind(gl);
454 for batch in self.batches.iter() {
455 batch.setup(gl);
456 gl.draw_elements_with_i32(
457 GL::TRIANGLES,
458 batch.indices.len() as i32,
459 GL::UNSIGNED_INT,
460 0,
461 );
462 }
463 }
464
465 pub fn clear(&mut self, color: [f32; 4]) {
467 let gl = &self.gl;
468 gl.clear_color(color[0], color[1], color[2], color[3]);
469 gl.clear(GL::COLOR_BUFFER_BIT);
470 }
471
472 pub fn add_component(&mut self, name: &'static str, component: Box<dyn Component>) {
474 self.components.insert(name, component);
475 }
476
477 pub fn init_components(&mut self) {
479 for component in self.components.values_mut() {
480 component.init()
481 }
482 }
483
484 pub fn update_components(&mut self, delta_time: f32) {
486 for component in self.components.values_mut() {
487 component.update(delta_time)
488 }
489 }
490
491 pub fn get_component<T: 'static + Component>(&self, key: &'static str) -> Result<&T, String> {
493 self.components
494 .get(key)
495 .unwrap()
496 .as_any()
497 .downcast_ref::<T>()
498 .ok_or_else(|| String::from("Could not cast to type."))
499 }
500
501 pub fn get_mut_component<T: 'static + Component>(
503 &mut self,
504 key: &'static str,
505 ) -> Result<&mut T, String> {
506 self.components
507 .get_mut(key)
508 .unwrap()
509 .as_mut_any()
510 .downcast_mut::<T>()
511 .ok_or_else(|| String::from("Could not cast to type."))
512 }
513
514 pub fn draw_components(&mut self) {
516 let gl = &self.gl;
517 let mut layers: Vec<Vec<Quad>> = self
518 .components
519 .values()
520 .filter_map(|component| component.get_quads())
521 .collect();
522 for layer in layers.iter_mut() {
523 let mut mesh = Mesh::new(
524 gl,
525 Vec::with_capacity(layer.len() * 4),
526 Vec::with_capacity(layer.len() * 6),
527 );
528 for (id, quad) in layer.iter_mut().enumerate() {
529 let last: u32 = id as u32 * 4;
530 mesh.vertices.append(&mut quad.get_vertices());
531 let mut indices = vec![last, last + 2, last + 1, last, last + 3, last + 2];
532 mesh.indices.append(&mut indices);
533 }
534 mesh.setup(gl);
535 gl.draw_elements_with_i32(
536 GL::TRIANGLES,
537 mesh.indices.len() as i32,
538 GL::UNSIGNED_INT,
539 0,
540 );
541 }
542 }
543}