use glam::{Vec2, Vec3, vec2, vec3};
use smallvec::smallvec;
use crate::{
Rgba, Rgba32Unmul,
context::RenderContext,
mesh::{CpuMesh, Material},
};
#[derive(Default)]
pub struct ShapeBuilder {
positions: Vec<Vec3>,
indices: Vec<glam::UVec3>,
}
impl ShapeBuilder {
pub fn add_convex_polygon(&mut self, points: &[Vec2]) {
re_log::debug_assert!(points.len() >= 3);
let base = self.positions.len() as u32;
for &p in points {
self.positions.push(vec3(p.x, p.y, 0.0));
}
for i in 1..(points.len() as u32 - 1) {
self.indices.push(glam::uvec3(base, base + i, base + i + 1));
}
}
pub fn add_triangle_fan(
&mut self,
center: Vec2,
ring: impl Fn(usize) -> Vec2,
segments: usize,
) {
let base = self.positions.len() as u32;
self.positions.push(vec3(center.x, center.y, 0.0));
for i in 0..segments {
let p = ring(i);
self.positions.push(vec3(p.x, p.y, 0.0));
}
for i in 0..segments as u32 {
let next = (i + 1) % segments as u32;
self.indices
.push(glam::uvec3(base, base + 1 + i, base + 1 + next));
}
}
pub fn add_segment(&mut self, a: Vec2, b: Vec2, half_width: f32) {
let dir = (b - a).normalize_or_zero();
let normal = vec2(-dir.y, dir.x) * half_width;
let p0 = a + normal;
let p1 = b + normal;
let p2 = b - normal;
let p3 = a - normal;
let base = self.positions.len() as u32;
self.positions.extend_from_slice(&[
vec3(p0.x, p0.y, 0.0),
vec3(p1.x, p1.y, 0.0),
vec3(p2.x, p2.y, 0.0),
vec3(p3.x, p3.y, 0.0),
]);
self.indices.push(glam::uvec3(base, base + 1, base + 2));
self.indices.push(glam::uvec3(base, base + 2, base + 3));
}
pub fn into_cpu_mesh(self, label: String, render_ctx: &RenderContext) -> CpuMesh {
let Self { positions, indices } = self;
let num_vertices = positions.len();
let index_count = (indices.len() * 3) as u32;
let bbox = macaw::BoundingBox::from_min_max(vec3(-1.0, -1.0, 0.0), vec3(1.0, 1.0, 0.0));
let albedo = render_ctx
.texture_manager_2d
.white_texture_unorm_handle()
.clone();
CpuMesh {
label: label.clone().into(),
triangle_indices: indices,
vertex_positions: positions,
vertex_colors: vec![Rgba32Unmul::WHITE; num_vertices],
vertex_normals: vec![vec3(0.0, 0.0, 1.0); num_vertices],
vertex_texcoords: vec![Vec2::ZERO; num_vertices],
materials: smallvec![Material {
label: label.into(),
index_range: 0..index_count,
albedo,
albedo_factor: Rgba::BLACK,
}],
bbox,
}
}
}