use crate::renderer::{
common::{PrimitiveType, Vertex},
render_core::Renderer,
Color, DrawCommandBuilder, InstanceData,
};
use glam::{Mat4, Vec3};
#[allow(clippy::wrong_self_convention)]
#[allow(dead_code)]
pub trait ShapeBuilder {
fn as_primitive(self) -> PrimitiveBuilder;
fn as_mesh(self) -> MeshBuilder;
}
#[derive(Clone)]
pub struct ShapeData {
pub vertices: Vec<Vertex>,
pub indices: Option<Vec<u32>>,
pub primitive_type: PrimitiveType,
pub transform: Mat4,
pub instances: Option<Vec<InstanceData>>,
}
impl ShapeData {
pub fn new(vertices: Vec<Vertex>, primitive_type: PrimitiveType) -> Self {
Self {
vertices,
indices: None,
primitive_type,
transform: Mat4::IDENTITY,
instances: None,
}
}
fn with_indices(mut self, indices: Vec<u32>) -> Self {
self.indices = Some(indices);
self
}
fn with_transform(mut self, transform: Mat4) -> Self {
self.transform = transform;
self
}
fn with_instances(mut self, instances: Vec<InstanceData>) -> Self {
self.instances = Some(instances);
self
}
}
impl ShapeBuilder for ShapeData {
fn as_primitive(self) -> PrimitiveBuilder {
PrimitiveBuilder { data: self }
}
fn as_mesh(self) -> MeshBuilder {
MeshBuilder { data: self }
}
}
pub struct PrimitiveBuilder {
data: ShapeData,
}
impl PrimitiveBuilder {
pub fn new(vertices: Vec<Vertex>, primitive_type: PrimitiveType) -> Self {
Self {
data: ShapeData::new(vertices, primitive_type),
}
}
#[allow(dead_code)]
pub fn with_indices(mut self, indices: Vec<u32>) -> Self {
self.data = self.data.with_indices(indices);
self
}
#[allow(dead_code)]
pub fn with_transform(mut self, transform: Mat4) -> Self {
self.data = self.data.with_transform(transform);
self
}
#[allow(dead_code)]
pub fn with_instances(mut self, instances: Vec<InstanceData>) -> Self {
self.data = self.data.with_instances(instances);
self
}
#[allow(dead_code)]
pub fn draw(self, renderer: &mut Renderer) {
let mut draw_command = DrawCommandBuilder::new_primitive(
self.data.vertices,
self.data.indices,
self.data.primitive_type,
)
.with_transform(self.data.transform);
if let Some(instances) = self.data.instances {
draw_command = draw_command.with_instances(instances);
}
renderer.draw_immediate(draw_command.build());
}
}
#[derive(Clone)]
pub struct MeshBuilder {
pub data: ShapeData,
}
impl MeshBuilder {
pub fn new(vertices: Vec<Vertex>, primitive_type: PrimitiveType) -> Self {
Self {
data: ShapeData::new(vertices, primitive_type),
}
}
#[allow(dead_code)]
pub fn with_indices(mut self, indices: Vec<u32>) -> Self {
self.data = self.data.with_indices(indices);
self
}
#[allow(dead_code)]
pub fn with_transform(mut self, transform: Mat4) -> Self {
self.data = self.data.with_transform(transform);
self
}
#[allow(dead_code)]
pub fn with_instances(mut self, instances: Vec<InstanceData>) -> Self {
self.data = self.data.with_instances(instances);
self
}
#[allow(dead_code)]
pub fn draw(&self, renderer: &mut Renderer) {
let mesh_id = renderer.add_mesh(self.clone());
let mut draw_command =
DrawCommandBuilder::new_mesh(mesh_id).with_transform(self.data.transform);
if let Some(instances) = &self.data.instances {
draw_command = draw_command.with_instances(instances.clone());
}
renderer.draw_immediate(draw_command.build());
}
}
pub fn vec3_color_to_vertex(position: Vec3, color: Color) -> Vertex {
Vertex {
position: position.to_array(),
color: color.into(),
}
}
#[cfg(test)]
mod tests {
use super::{vec3_color_to_vertex, MeshBuilder, PrimitiveBuilder};
use crate::renderer::{
common::{PrimitiveType, Vertex},
Color, InstanceData,
};
use glam::{Mat4, Vec3};
fn create_sample_triangle() -> Vec<Vertex> {
vec![
Vertex {
position: [0.0, 0.5, 0.0],
color: [1.0, 0.0, 0.0, 1.0],
},
Vertex {
position: [-0.5, -0.5, 0.0],
color: [0.0, 1.0, 0.0, 1.0],
},
Vertex {
position: [0.5, -0.5, 0.0],
color: [0.0, 0.0, 1.0, 1.0],
},
]
}
#[test]
fn test_primitive_builder() {
let vertices = create_sample_triangle();
let builder = PrimitiveBuilder::new(vertices.clone(), PrimitiveType::Triangle)
.with_indices(vec![0, 1, 2])
.with_transform(Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0)))
.with_instances(vec![InstanceData::new(
Mat4::IDENTITY,
Color::new(1.0, 0.0, 0.0, 1.0),
)]);
assert_eq!(builder.data.vertices, vertices);
assert_eq!(builder.data.primitive_type, PrimitiveType::Triangle);
assert_eq!(builder.data.indices, Some(vec![0, 1, 2]));
assert_eq!(
builder.data.transform,
Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0))
);
assert!(builder.data.instances.is_some());
}
#[test]
fn test_mesh_builder() {
let vertices = create_sample_triangle();
let builder = MeshBuilder::new(vertices.clone(), PrimitiveType::Triangle)
.with_indices(vec![0, 1, 2])
.with_transform(Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0)))
.with_instances(vec![InstanceData::new(
Mat4::IDENTITY,
Color::new(1.0, 0.0, 0.0, 1.0),
)]);
assert_eq!(builder.data.vertices, vertices);
assert_eq!(builder.data.primitive_type, PrimitiveType::Triangle);
assert_eq!(builder.data.indices, Some(vec![0, 1, 2]));
assert_eq!(
builder.data.transform,
Mat4::from_translation(Vec3::new(1.0, 2.0, 3.0))
);
assert!(builder.data.instances.is_some());
}
#[test]
fn test_vec3_color_to_vertex() {
let position = Vec3::new(1.0, 2.0, 3.0);
let color = Color::new(0.1, 0.2, 0.3, 1.0);
let vertex = vec3_color_to_vertex(position, color);
assert_eq!(vertex.position, [1.0, 2.0, 3.0]);
assert_eq!(vertex.color, [0.1, 0.2, 0.3, 1.0]);
}
}