1use crate::core::*;
2use crate::renderer::*;
3
4pub struct Wireframe {
9 material: WireframeMaterial,
10 positions: VertexBuffer<Vec3>,
11 barycentric: VertexBuffer<Vec3>,
12 context: Context,
13 aabb: AxisAlignedBoundingBox,
14 transformation: Mat4,
15}
16
17impl Wireframe {
18 pub fn new(context: &Context, positions: &[Vec3], wire_width: f32, wire_color: Srgba) -> Self {
20 let barycentric = VertexBuffer::new_with_data(
21 context,
22 &(0..positions.len() / 3)
23 .flat_map(|_| [vec3(1., 0., 0.), vec3(0., 1., 0.), vec3(0., 0., 1.)])
24 .collect::<Vec<_>>(),
25 );
26 Self {
27 material: material::WireframeMaterial {
28 line_width: wire_width,
29 line_color: wire_color,
30 },
31 positions: VertexBuffer::new_with_data(context, positions),
32 barycentric,
33 context: context.clone(),
34 aabb: AxisAlignedBoundingBox::new_with_positions(positions),
35 transformation: Mat4::identity(),
36 }
37 }
38
39 pub fn new_from_cpu_mesh(
41 context: &Context,
42 cpu_mesh: &CpuMesh,
43 wire_width: f32,
44 wire_color: Srgba,
45 ) -> Self {
46 let positions = if let Some(indices) = cpu_mesh.indices.to_u32() {
47 let source_positions = cpu_mesh.positions.to_f32();
48 indices
49 .into_iter()
50 .map(|index| source_positions[index as usize])
51 .collect()
52 } else {
53 cpu_mesh.positions.to_f32()
54 };
55 Self::new(context, &positions, wire_width, wire_color)
56 }
57
58 pub fn new_from_cpu_model(
60 context: &Context,
61 cpu_model: &CpuModel,
62 wire_width: f32,
63 wire_color: Srgba,
64 ) -> Vec<Self> {
65 cpu_model
66 .geometries
67 .iter()
68 .filter_map(|g| match &g.geometry {
69 three_d_asset::Geometry::Triangles(mesh) => {
70 let mut wireframe =
71 Wireframe::new_from_cpu_mesh(context, mesh, wire_width, wire_color);
72 wireframe.set_transformation(g.transformation);
73 Some(wireframe)
74 }
75 _ => None,
76 })
77 .collect::<Vec<_>>()
78 }
79
80 pub fn set_transformation(&mut self, transformation: Mat4) {
82 self.transformation = transformation
83 }
84
85 pub fn set_wire_width(&mut self, width: f32) {
87 self.material.line_width = width;
88 }
89
90 pub fn set_wire_color(&mut self, color: Srgba) {
92 self.material.line_color = color;
93 }
94}
95
96impl<'a> IntoIterator for &'a Wireframe {
97 type Item = &'a dyn Object;
98 type IntoIter = std::iter::Once<&'a dyn Object>;
99
100 fn into_iter(self) -> Self::IntoIter {
101 std::iter::once(self)
102 }
103}
104
105impl Object for Wireframe {
106 fn render(&self, viewer: &dyn Viewer, lights: &[&dyn Light]) {
107 if let Err(e) = render_with_material(&self.context, viewer, self, &self.material, lights) {
108 panic!("{}", e.to_string());
109 }
110 }
111
112 fn material_type(&self) -> MaterialType {
113 self.material.material_type()
114 }
115}
116
117impl Geometry for Wireframe {
118 fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
119 program.use_uniform("viewProjection", viewer.projection() * viewer.view());
120 program.use_uniform("modelMatrix", self.transformation);
121 program.use_vertex_attribute("position", &self.positions);
122 program.use_vertex_attribute("barycentric", &self.barycentric);
123 program.draw_arrays(
124 render_states,
125 viewer.viewport(),
126 self.positions.vertex_count(),
127 )
128 }
129
130 fn vertex_shader_source(&self) -> String {
131 include_str!("shaders/wireframe.vert").to_owned()
132 }
133
134 fn id(&self) -> GeometryId {
135 GeometryId::Wireframe
136 }
137
138 fn render_with_material(
139 &self,
140 material: &dyn Material,
141 viewer: &dyn Viewer,
142 lights: &[&dyn Light],
143 ) {
144 if let Err(e) = render_with_material(&self.context, viewer, &self, material, lights) {
145 panic!("{}", e.to_string());
146 }
147 }
148
149 fn render_with_effect(
150 &self,
151 material: &dyn Effect,
152 viewer: &dyn Viewer,
153 lights: &[&dyn Light],
154 color_texture: Option<ColorTexture>,
155 depth_texture: Option<DepthTexture>,
156 ) {
157 if let Err(e) = render_with_effect(
158 &self.context,
159 viewer,
160 self,
161 material,
162 lights,
163 color_texture,
164 depth_texture,
165 ) {
166 panic!("{}", e.to_string());
167 }
168 }
169
170 fn aabb(&self) -> AxisAlignedBoundingBox {
171 self.aabb.transformed(self.transformation)
172 }
173}