j_webgl/structs/renderable/
cube_with_normals.rs

1use super::*;
2
3struct Inner {
4  program: web_sys::WebGlProgram,
5  vao: web_sys::WebGlVertexArrayObject,
6  matrix_location: web_sys::WebGlUniformLocation,
7}
8
9#[wasm_bindgen::prelude::wasm_bindgen]
10#[derive(Default)]
11pub struct CubeWithNormals {
12  inner: std::cell::RefCell<Option<Inner>>,
13}
14
15#[wasm_bindgen::prelude::wasm_bindgen]
16impl CubeWithNormals {
17  pub fn new() -> Result<CubeWithNormals> {
18    Ok(CubeWithNormals { inner: std::cell::RefCell::new(None), })
19  }
20}
21
22impl traits::Renderable for CubeWithNormals {
23  fn render(
24    &self,
25    context: &web_sys::WebGl2RenderingContext,
26    camera: &[f32],
27  ) -> Result<()>
28  {
29    if self.inner.borrow().is_none() {
30      let program = utils::compile_program(
31        context,
32        shaders::vertex::matrix_position_normal()?,
33        shaders::fragment::color_light()?,
34      )?;
35
36      let position_attribute_location = context.get_attrib_location(&program, "a_position");
37      let normal_attribute_location = context.get_attrib_location(&program, "a_normal");
38      let matrix_location = context.get_uniform_location(&program, "u_matrix");
39      let color_location = context.get_uniform_location(&program, "u_color");
40      let reverse_light_direction_location = context.get_uniform_location(&program, "u_reverseLightDirection");
41
42      let vertices: [f32; 24] = [
43            // Front face
44            -0.5, -0.5,  0.5,  // 0: bottom-left-front
45             0.5, -0.5,  0.5,  // 1: bottom-right-front
46             0.5,  0.5,  0.5,  // 2: top-right-front
47            -0.5,  0.5,  0.5,  // 3: top-left-front
48            // Back face
49            -0.5, -0.5, -0.5,  // 4: bottom-left-back
50             0.5, -0.5, -0.5,  // 5: bottom-right-back
51             0.5,  0.5, -0.5,  // 6: top-right-back
52            -0.5,  0.5, -0.5,  // 7: top-left-back
53      ];
54
55      // Cube indices: 12 triangles (2 per face) = 36 indices
56      let indices: [usize; 36] = [
57            // Front face
58            0, 1, 2,  2, 3, 0,
59            // Back face
60            4, 6, 5,  6, 4, 7,
61            // Top face
62            3, 2, 6,  6, 7, 3,
63            // Bottom face
64            0, 4, 5,  5, 1, 0,
65            // Right face
66            1, 5, 6,  6, 2, 1,
67            // Left face
68            0, 3, 7,  7, 4, 0,
69      ];
70      let mut normals = Vec::<f32>::new();
71      for _ in 0..6 { normals.append(&mut vec![ 0.0, 0.0, 1.0, ]); }  // Front face
72      for _ in 0..6 { normals.append(&mut vec![ 0.0, 0.0, -1.0, ]); } // Back face
73      for _ in 0..6 { normals.append(&mut vec![ 0.0, 1.0,  0.0, ]); } // Top face
74      for _ in 0..6 { normals.append(&mut vec![ 0.0, -1.0, 0.0, ]); } // Bottom face
75      for _ in 0..6 { normals.append(&mut vec![ 1.0, 0.0,  0.0, ]); } // Right face
76      for _ in 0..6 { normals.append(&mut vec![-1.0, 0.0,  0.0, ]); } // Left face
77
78      let array: Vec<f32> = indices.iter()
79      .fold(Vec::new(), |mut a, i| {
80          a.push(vertices[*i*3]);
81          a.push(vertices[*i*3+1]);
82          a.push(vertices[*i*3+2]);
83          a
84      });
85
86      // Position
87      let position_buffer = context.create_buffer().unwrap();
88      let vao = context.create_vertex_array().unwrap();
89      context.bind_vertex_array(Some(&vao));
90      context.enable_vertex_attrib_array(position_attribute_location as u32);
91      context.bind_buffer(web_sys::WebGl2RenderingContext::ARRAY_BUFFER, Some(&position_buffer));
92      unsafe {
93          let vertices_array = js_sys::Float32Array::view(array.as_slice());
94          context.buffer_data_with_array_buffer_view(
95                web_sys::WebGl2RenderingContext::ARRAY_BUFFER,
96                &vertices_array,
97                web_sys::WebGl2RenderingContext::STATIC_DRAW,
98          );
99      }
100      context.vertex_attrib_pointer_with_i32(position_attribute_location as u32,
101          3, // size
102          web_sys::WebGl2RenderingContext::FLOAT,
103          false, // don't normalize
104          0, // stride
105          0, // offset
106      );
107
108
109      // Normals
110      let normal_buffer = context.create_buffer().unwrap();
111      context.enable_vertex_attrib_array(normal_attribute_location as u32);
112      context.bind_buffer(web_sys::WebGl2RenderingContext::ARRAY_BUFFER, Some(&normal_buffer));
113      unsafe {
114          let array = js_sys::Float32Array::view(normals.as_slice());
115          context.buffer_data_with_array_buffer_view(
116                web_sys::WebGl2RenderingContext::ARRAY_BUFFER,
117                &array,
118                web_sys::WebGl2RenderingContext::STATIC_DRAW,
119          );
120      }
121      context.vertex_attrib_pointer_with_i32(normal_attribute_location as u32,
122          3, // size
123          web_sys::WebGl2RenderingContext::FLOAT,
124          false, // don't normalize
125          0, // stride
126          0, // offset
127      );
128
129      // Color
130      context.use_program(Some(&program));
131      context.uniform4f(
132        color_location.as_ref(),
133        0.2, // R
134        1.0, // G
135        0.2, // B
136        1.0, // Alpha
137      );
138
139      // Light
140      context.uniform3f(
141        reverse_light_direction_location.as_ref(),
142        0.5, 0.7, 1.0,
143      );
144
145      *self.inner.borrow_mut() = Some(
146        Inner {
147          program,
148          vao,
149          matrix_location: matrix_location.unwrap(),
150        }
151      );
152    }
153
154    let binding = self.inner.borrow();
155    let inner = binding.as_ref().unwrap();
156
157    context.use_program(Some(&inner.program));
158    context.bind_vertex_array(Some(&inner.vao));
159    context.uniform_matrix4fv_with_f32_array(
160      Some(&inner.matrix_location),
161      false,
162      camera,
163    );
164    context.draw_arrays(
165          web_sys::WebGl2RenderingContext::TRIANGLES,
166          0, // offset
167          12 * 3, // count
168    );
169
170    Ok(())
171  }
172}