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 TriangleBuffer {
249 Unindexed {
252 number_of_vertices: u32,
254 },
255 IndexedU8(ElementBuffer<u8>),
259 IndexedU16(ElementBuffer<u16>),
263 IndexedU32(ElementBuffer<u32>),
267}
268
269impl TriangleBuffer {
270 pub fn new(context: &Context, cpu_mesh: &CpuMesh) -> Self {
272 match &cpu_mesh.indices {
273 Indices::U8(ind) => Self::IndexedU8(ElementBuffer::new_with_data(context, ind)),
274 Indices::U16(ind) => Self::IndexedU16(ElementBuffer::new_with_data(context, ind)),
275 Indices::U32(ind) => Self::IndexedU32(ElementBuffer::new_with_data(context, ind)),
276 Indices::None => Self::Unindexed {
277 number_of_vertices: cpu_mesh.vertex_count() as u32,
278 },
279 }
280 }
281
282 pub fn draw(&self, program: &Program, render_states: RenderStates, viewer: &dyn Viewer) {
284 match self {
285 Self::Unindexed { number_of_vertices } => {
286 program.draw_arrays(render_states, viewer.viewport(), *number_of_vertices)
287 }
288 Self::IndexedU8(element_buffer) => {
289 program.draw_elements(render_states, viewer.viewport(), element_buffer)
290 }
291 Self::IndexedU16(element_buffer) => {
292 program.draw_elements(render_states, viewer.viewport(), element_buffer)
293 }
294 Self::IndexedU32(element_buffer) => {
295 program.draw_elements(render_states, viewer.viewport(), element_buffer)
296 }
297 }
298 }
299
300 pub fn draw_instanced(
302 &self,
303 program: &Program,
304 render_states: RenderStates,
305 viewer: &dyn Viewer,
306 instance_count: u32,
307 ) {
308 match self {
309 Self::Unindexed { number_of_vertices } => program.draw_arrays_instanced(
310 render_states,
311 viewer.viewport(),
312 *number_of_vertices,
313 instance_count,
314 ),
315 Self::IndexedU8(element_buffer) => program.draw_elements_instanced(
316 render_states,
317 viewer.viewport(),
318 element_buffer,
319 instance_count,
320 ),
321 Self::IndexedU16(element_buffer) => program.draw_elements_instanced(
322 render_states,
323 viewer.viewport(),
324 element_buffer,
325 instance_count,
326 ),
327 Self::IndexedU32(element_buffer) => program.draw_elements_instanced(
328 render_states,
329 viewer.viewport(),
330 element_buffer,
331 instance_count,
332 ),
333 }
334 }
335
336 pub fn vertex_count(&self) -> u32 {
338 match self {
339 Self::Unindexed { number_of_vertices } => *number_of_vertices,
340 Self::IndexedU8(element_buffer) => element_buffer.count(),
341 Self::IndexedU16(element_buffer) => element_buffer.count(),
342 Self::IndexedU32(element_buffer) => element_buffer.count(),
343 }
344 }
345
346 pub fn triangle_count(&self) -> u32 {
348 self.vertex_count() / 3
349 }
350}
351
352struct BaseMesh {
353 indices: TriangleBuffer,
354 positions: VertexBuffer<Vec3>,
355 normals: Option<VertexBuffer<Vec3>>,
356 tangents: Option<VertexBuffer<Vec4>>,
357 uvs: Option<VertexBuffer<Vec2>>,
358 colors: Option<VertexBuffer<Vec4>>,
359}
360
361impl BaseMesh {
362 pub fn new(context: &Context, cpu_mesh: &CpuMesh) -> Self {
363 #[cfg(debug_assertions)]
364 cpu_mesh.validate().expect("invalid cpu mesh");
365
366 Self {
367 indices: TriangleBuffer::new(context, cpu_mesh),
368 positions: VertexBuffer::new_with_data(context, &cpu_mesh.positions.to_f32()),
369 normals: cpu_mesh
370 .normals
371 .as_ref()
372 .map(|data| VertexBuffer::new_with_data(context, data)),
373 tangents: cpu_mesh
374 .tangents
375 .as_ref()
376 .map(|data| VertexBuffer::new_with_data(context, data)),
377 uvs: cpu_mesh.uvs.as_ref().map(|data| {
378 VertexBuffer::new_with_data(
379 context,
380 &data
381 .iter()
382 .map(|uv| vec2(uv.x, 1.0 - uv.y))
383 .collect::<Vec<_>>(),
384 )
385 }),
386 colors: cpu_mesh.colors.as_ref().map(|data| {
387 VertexBuffer::new_with_data(
388 context,
389 &data.iter().map(|c| c.to_linear_srgb()).collect::<Vec<_>>(),
390 )
391 }),
392 }
393 }
394
395 pub fn draw(&self, program: &Program, render_states: RenderStates, viewer: &dyn Viewer) {
396 self.use_attributes(program);
397 self.indices.draw(program, render_states, viewer);
398 }
399
400 pub fn draw_instanced(
401 &self,
402 program: &Program,
403 render_states: RenderStates,
404 viewer: &dyn Viewer,
405 instance_count: u32,
406 ) {
407 self.use_attributes(program);
408 self.indices
409 .draw_instanced(program, render_states, viewer, instance_count);
410 }
411
412 fn use_attributes(&self, program: &Program) {
413 program.use_vertex_attribute("position", &self.positions);
414
415 if program.requires_attribute("normal") {
416 if let Some(normals) = &self.normals {
417 program.use_vertex_attribute("normal", normals);
418 }
419 }
420
421 if program.requires_attribute("tangent") {
422 if let Some(tangents) = &self.tangents {
423 program.use_vertex_attribute("tangent", tangents);
424 }
425 }
426
427 if program.requires_attribute("uv_coordinates") {
428 if let Some(uvs) = &self.uvs {
429 program.use_vertex_attribute("uv_coordinates", uvs);
430 }
431 }
432
433 if program.requires_attribute("color") {
434 if let Some(colors) = &self.colors {
435 program.use_vertex_attribute("color", colors);
436 }
437 }
438 }
439
440 fn vertex_shader_source(&self) -> String {
441 format!(
442 "{}{}{}{}{}{}",
443 if self.normals.is_some() {
444 "#define USE_NORMALS\n"
445 } else {
446 ""
447 },
448 if self.tangents.is_some() {
449 "#define USE_TANGENTS\n"
450 } else {
451 ""
452 },
453 if self.uvs.is_some() {
454 "#define USE_UVS\n"
455 } else {
456 ""
457 },
458 if self.colors.is_some() {
459 "#define USE_VERTEX_COLORS\n"
460 } else {
461 ""
462 },
463 include_str!("../core/shared.frag"),
464 include_str!("geometry/shaders/mesh.vert"),
465 )
466 }
467}