1#![macro_use]
2macro_rules! impl_geometry_body {
9 ($inner:ident) => {
10 fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
11 self.$inner().draw(viewer, program, render_states)
12 }
13
14 fn vertex_shader_source(&self) -> String {
15 self.$inner().vertex_shader_source()
16 }
17
18 fn id(&self) -> GeometryId {
19 self.$inner().id()
20 }
21
22 fn render_with_material(
23 &self,
24 material: &dyn Material,
25 viewer: &dyn Viewer,
26 lights: &[&dyn Light],
27 ) {
28 self.$inner().render_with_material(material, viewer, lights)
29 }
30
31 fn render_with_effect(
32 &self,
33 material: &dyn Effect,
34 viewer: &dyn Viewer,
35 lights: &[&dyn Light],
36 color_texture: Option<ColorTexture>,
37 depth_texture: Option<DepthTexture>,
38 ) {
39 self.$inner()
40 .render_with_effect(material, viewer, lights, color_texture, depth_texture)
41 }
42
43 fn aabb(&self) -> AxisAlignedBoundingBox {
44 self.$inner().aabb()
45 }
46 };
47}
48
49mod mesh;
50#[doc(inline)]
51pub use mesh::*;
52
53mod instanced_mesh;
54#[doc(inline)]
55pub use instanced_mesh::*;
56
57mod sprites;
58#[doc(inline)]
59pub use sprites::*;
60
61mod particles;
62#[doc(inline)]
63pub use particles::*;
64
65mod bounding_box;
66#[doc(inline)]
67pub use bounding_box::*;
68
69mod line;
70#[doc(inline)]
71pub use line::*;
72
73mod rectangle;
74#[doc(inline)]
75pub use rectangle::*;
76
77mod circle;
78#[doc(inline)]
79pub use circle::*;
80
81use crate::core::*;
82use crate::renderer::*;
83
84pub use three_d_asset::{
85 Geometry as CpuGeometry, Indices, KeyFrameAnimation, KeyFrames, PointCloud, Positions,
86 TriMesh as CpuMesh,
87};
88
89pub trait Geometry {
106 fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates);
110
111 fn vertex_shader_source(&self) -> String;
115
116 fn id(&self) -> GeometryId;
123
124 fn render_with_material(
130 &self,
131 material: &dyn Material,
132 viewer: &dyn Viewer,
133 lights: &[&dyn Light],
134 );
135
136 fn render_with_effect(
142 &self,
143 material: &dyn Effect,
144 viewer: &dyn Viewer,
145 lights: &[&dyn Light],
146 color_texture: Option<ColorTexture>,
147 depth_texture: Option<DepthTexture>,
148 );
149
150 fn aabb(&self) -> AxisAlignedBoundingBox;
154
155 fn animate(&mut self, _time: f32) {}
160}
161
162use std::ops::Deref;
163impl<T: Geometry + ?Sized> Geometry for &T {
164 impl_geometry_body!(deref);
165}
166
167impl<T: Geometry + ?Sized> Geometry for &mut T {
168 impl_geometry_body!(deref);
169
170 fn animate(&mut self, time: f32) {
171 self.deref().animate(time)
172 }
173}
174
175impl<T: Geometry> Geometry for Box<T> {
176 impl_geometry_body!(as_ref);
177}
178
179impl<T: Geometry> Geometry for std::rc::Rc<T> {
180 impl_geometry_body!(as_ref);
181}
182
183impl<T: Geometry> Geometry for std::sync::Arc<T> {
184 impl_geometry_body!(as_ref);
185}
186
187impl<T: Geometry> Geometry for std::cell::RefCell<T> {
188 impl_geometry_body!(borrow);
189
190 fn animate(&mut self, time: f32) {
191 self.borrow_mut().animate(time)
192 }
193}
194
195impl<T: Geometry> Geometry for std::sync::RwLock<T> {
196 fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
197 self.read().unwrap().draw(viewer, program, render_states)
198 }
199
200 fn vertex_shader_source(&self) -> String {
201 self.read().unwrap().vertex_shader_source()
202 }
203
204 fn id(&self) -> GeometryId {
205 self.read().unwrap().id()
206 }
207
208 fn render_with_material(
209 &self,
210 material: &dyn Material,
211 viewer: &dyn Viewer,
212 lights: &[&dyn Light],
213 ) {
214 self.read()
215 .unwrap()
216 .render_with_material(material, viewer, lights)
217 }
218
219 fn render_with_effect(
220 &self,
221 material: &dyn Effect,
222 viewer: &dyn Viewer,
223 lights: &[&dyn Light],
224 color_texture: Option<ColorTexture>,
225 depth_texture: Option<DepthTexture>,
226 ) {
227 self.read().unwrap().render_with_effect(
228 material,
229 viewer,
230 lights,
231 color_texture,
232 depth_texture,
233 )
234 }
235
236 fn aabb(&self) -> AxisAlignedBoundingBox {
237 self.read().unwrap().aabb()
238 }
239
240 fn animate(&mut self, time: f32) {
241 self.write().unwrap().animate(time)
242 }
243}
244
245pub enum IndexBuffer {
251 None,
253 U8(ElementBuffer<u8>),
255 U16(ElementBuffer<u16>),
257 U32(ElementBuffer<u32>),
259}
260
261struct BaseMesh {
262 indices: IndexBuffer,
263 positions: VertexBuffer<Vec3>,
264 normals: Option<VertexBuffer<Vec3>>,
265 tangents: Option<VertexBuffer<Vec4>>,
266 uvs: Option<VertexBuffer<Vec2>>,
267 colors: Option<VertexBuffer<Vec4>>,
268}
269
270impl BaseMesh {
271 pub fn new(context: &Context, cpu_mesh: &CpuMesh) -> Self {
272 #[cfg(debug_assertions)]
273 cpu_mesh.validate().expect("invalid cpu mesh");
274
275 Self {
276 indices: match &cpu_mesh.indices {
277 Indices::U8(ind) => IndexBuffer::U8(ElementBuffer::new_with_data(context, ind)),
278 Indices::U16(ind) => IndexBuffer::U16(ElementBuffer::new_with_data(context, ind)),
279 Indices::U32(ind) => IndexBuffer::U32(ElementBuffer::new_with_data(context, ind)),
280 Indices::None => IndexBuffer::None,
281 },
282 positions: VertexBuffer::new_with_data(context, &cpu_mesh.positions.to_f32()),
283 normals: cpu_mesh
284 .normals
285 .as_ref()
286 .map(|data| VertexBuffer::new_with_data(context, data)),
287 tangents: cpu_mesh
288 .tangents
289 .as_ref()
290 .map(|data| VertexBuffer::new_with_data(context, data)),
291 uvs: cpu_mesh.uvs.as_ref().map(|data| {
292 VertexBuffer::new_with_data(
293 context,
294 &data
295 .iter()
296 .map(|uv| vec2(uv.x, 1.0 - uv.y))
297 .collect::<Vec<_>>(),
298 )
299 }),
300 colors: cpu_mesh.colors.as_ref().map(|data| {
301 VertexBuffer::new_with_data(
302 context,
303 &data.iter().map(|c| c.to_linear_srgb()).collect::<Vec<_>>(),
304 )
305 }),
306 }
307 }
308
309 pub fn draw(&self, program: &Program, render_states: RenderStates, viewer: &dyn Viewer) {
310 self.use_attributes(program);
311
312 match &self.indices {
313 IndexBuffer::None => program.draw_arrays(
314 render_states,
315 viewer.viewport(),
316 self.positions.vertex_count(),
317 ),
318 IndexBuffer::U8(element_buffer) => {
319 program.draw_elements(render_states, viewer.viewport(), element_buffer)
320 }
321 IndexBuffer::U16(element_buffer) => {
322 program.draw_elements(render_states, viewer.viewport(), element_buffer)
323 }
324 IndexBuffer::U32(element_buffer) => {
325 program.draw_elements(render_states, viewer.viewport(), element_buffer)
326 }
327 }
328 }
329
330 pub fn draw_instanced(
331 &self,
332 program: &Program,
333 render_states: RenderStates,
334 viewer: &dyn Viewer,
335 instance_count: u32,
336 ) {
337 self.use_attributes(program);
338
339 match &self.indices {
340 IndexBuffer::None => program.draw_arrays_instanced(
341 render_states,
342 viewer.viewport(),
343 self.positions.vertex_count(),
344 instance_count,
345 ),
346 IndexBuffer::U8(element_buffer) => program.draw_elements_instanced(
347 render_states,
348 viewer.viewport(),
349 element_buffer,
350 instance_count,
351 ),
352 IndexBuffer::U16(element_buffer) => program.draw_elements_instanced(
353 render_states,
354 viewer.viewport(),
355 element_buffer,
356 instance_count,
357 ),
358 IndexBuffer::U32(element_buffer) => program.draw_elements_instanced(
359 render_states,
360 viewer.viewport(),
361 element_buffer,
362 instance_count,
363 ),
364 }
365 }
366
367 fn use_attributes(&self, program: &Program) {
368 program.use_vertex_attribute("position", &self.positions);
369
370 if program.requires_attribute("normal") {
371 if let Some(normals) = &self.normals {
372 program.use_vertex_attribute("normal", normals);
373 }
374 }
375
376 if program.requires_attribute("tangent") {
377 if let Some(tangents) = &self.tangents {
378 program.use_vertex_attribute("tangent", tangents);
379 }
380 }
381
382 if program.requires_attribute("uv_coordinates") {
383 if let Some(uvs) = &self.uvs {
384 program.use_vertex_attribute("uv_coordinates", uvs);
385 }
386 }
387
388 if program.requires_attribute("color") {
389 if let Some(colors) = &self.colors {
390 program.use_vertex_attribute("color", colors);
391 }
392 }
393 }
394
395 fn vertex_shader_source(&self) -> String {
396 format!(
397 "{}{}{}{}{}{}",
398 if self.normals.is_some() {
399 "#define USE_NORMALS\n"
400 } else {
401 ""
402 },
403 if self.tangents.is_some() {
404 "#define USE_TANGENTS\n"
405 } else {
406 ""
407 },
408 if self.uvs.is_some() {
409 "#define USE_UVS\n"
410 } else {
411 ""
412 },
413 if self.colors.is_some() {
414 "#define USE_VERTEX_COLORS\n"
415 } else {
416 ""
417 },
418 include_str!("../core/shared.frag"),
419 include_str!("geometry/shaders/mesh.vert"),
420 )
421 }
422}