use crate::core::*;
use crate::renderer::*;
pub struct Wireframe {
material: WireframeMaterial,
positions: VertexBuffer<Vec3>,
barycentric: VertexBuffer<Vec3>,
context: Context,
aabb: AxisAlignedBoundingBox,
transformation: Mat4,
}
impl Wireframe {
pub fn new(context: &Context, positions: &[Vec3], wire_width: f32, wire_color: Srgba) -> Self {
let barycentric = VertexBuffer::new_with_data(
context,
&(0..positions.len() / 3)
.flat_map(|_| [vec3(1., 0., 0.), vec3(0., 1., 0.), vec3(0., 0., 1.)])
.collect::<Vec<_>>(),
);
Self {
material: material::WireframeMaterial {
line_width: wire_width,
line_color: wire_color,
},
positions: VertexBuffer::new_with_data(context, positions),
barycentric,
context: context.clone(),
aabb: AxisAlignedBoundingBox::new_with_positions(positions),
transformation: Mat4::identity(),
}
}
pub fn new_from_cpu_mesh(
context: &Context,
cpu_mesh: &CpuMesh,
wire_width: f32,
wire_color: Srgba,
) -> Self {
let positions = if let Some(indices) = cpu_mesh.indices.to_u32() {
let source_positions = cpu_mesh.positions.to_f32();
indices
.into_iter()
.map(|index| source_positions[index as usize])
.collect()
} else {
cpu_mesh.positions.to_f32()
};
Self::new(context, &positions, wire_width, wire_color)
}
pub fn new_from_cpu_model(
context: &Context,
cpu_model: &CpuModel,
wire_width: f32,
wire_color: Srgba,
) -> Vec<Self> {
cpu_model
.geometries
.iter()
.filter_map(|g| match &g.geometry {
three_d_asset::Geometry::Triangles(mesh) => {
let mut wireframe =
Wireframe::new_from_cpu_mesh(context, mesh, wire_width, wire_color);
wireframe.set_transformation(g.transformation);
Some(wireframe)
}
_ => None,
})
.collect::<Vec<_>>()
}
pub fn set_transformation(&mut self, transformation: Mat4) {
self.transformation = transformation
}
pub fn set_wire_width(&mut self, width: f32) {
self.material.line_width = width;
}
pub fn set_wire_color(&mut self, color: Srgba) {
self.material.line_color = color;
}
}
impl<'a> IntoIterator for &'a Wireframe {
type Item = &'a dyn Object;
type IntoIter = std::iter::Once<&'a dyn Object>;
fn into_iter(self) -> Self::IntoIter {
std::iter::once(self)
}
}
impl Object for Wireframe {
fn render(&self, viewer: &dyn Viewer, lights: &[&dyn Light]) {
if let Err(e) = render_with_material(&self.context, viewer, self, &self.material, lights) {
panic!("{}", e.to_string());
}
}
fn material_type(&self) -> MaterialType {
self.material.material_type()
}
}
impl Geometry for Wireframe {
fn draw(&self, viewer: &dyn Viewer, program: &Program, render_states: RenderStates) {
program.use_uniform("viewProjection", viewer.projection() * viewer.view());
program.use_uniform("modelMatrix", self.transformation);
program.use_vertex_attribute("position", &self.positions);
program.use_vertex_attribute("barycentric", &self.barycentric);
program.draw_arrays(
render_states,
viewer.viewport(),
self.positions.vertex_count(),
)
}
fn vertex_shader_source(&self) -> String {
include_str!("shaders/wireframe.vert").to_owned()
}
fn id(&self) -> GeometryId {
GeometryId::Wireframe
}
fn render_with_material(
&self,
material: &dyn Material,
viewer: &dyn Viewer,
lights: &[&dyn Light],
) {
if let Err(e) = render_with_material(&self.context, viewer, &self, material, lights) {
panic!("{}", e.to_string());
}
}
fn render_with_effect(
&self,
material: &dyn Effect,
viewer: &dyn Viewer,
lights: &[&dyn Light],
color_texture: Option<ColorTexture>,
depth_texture: Option<DepthTexture>,
) {
if let Err(e) = render_with_effect(
&self.context,
viewer,
self,
material,
lights,
color_texture,
depth_texture,
) {
panic!("{}", e.to_string());
}
}
fn aabb(&self) -> AxisAlignedBoundingBox {
self.aabb.transformed(self.transformation)
}
}