use crate::context::WgpuContext;
use crate::renderer::geometry::{Aabb, Geometry};
use crate::renderer::light::Light;
use crate::renderer::material::Material;
use crate::renderer::viewer::Viewer;
use glam::Mat4;
pub trait Object {
fn render(
&self,
ctx: &WgpuContext,
viewer: &dyn Viewer,
lights: &[&dyn Light],
render_pass: &mut wgpu::RenderPass<'_>,
);
fn aabb(&self) -> Aabb;
fn transform(&self) -> Mat4;
fn set_transform(&mut self, transform: Mat4);
}
pub struct Gm<G: Geometry, M: Material> {
pub geometry: G,
pub material: M,
pub transform: Mat4,
}
impl<G: Geometry, M: Material> Gm<G, M> {
pub fn new(geometry: G, material: M) -> Self {
Self {
geometry,
material,
transform: Mat4::IDENTITY,
}
}
pub fn with_transform(mut self, transform: Mat4) -> Self {
self.transform = transform;
self
}
pub fn with_position(mut self, x: f32, y: f32, z: f32) -> Self {
self.transform = Mat4::from_translation(glam::Vec3::new(x, y, z));
self
}
pub fn update_material(&self, ctx: &WgpuContext, viewer: &dyn Viewer, lights: &[&dyn Light]) {
self.material
.update_uniforms(ctx, viewer, self.transform, lights);
}
}
impl<G: Geometry, M: Material> Object for Gm<G, M> {
fn render(
&self,
ctx: &WgpuContext,
viewer: &dyn Viewer,
lights: &[&dyn Light],
render_pass: &mut wgpu::RenderPass<'_>,
) {
self.material
.update_uniforms(ctx, viewer, self.transform, lights);
render_pass.set_pipeline(self.material.pipeline());
render_pass.set_bind_group(0, self.material.camera_bind_group(), &[]);
render_pass.set_bind_group(1, self.material.model_bind_group(), &[]);
render_pass.set_vertex_buffer(0, self.geometry.vertex_buffer().slice());
if let Some(index_buffer) = self.geometry.index_buffer() {
render_pass.set_index_buffer(index_buffer.slice(), index_buffer.format());
render_pass.draw_indexed(0..self.geometry.draw_count(), 0, 0..1);
} else {
render_pass.draw(0..self.geometry.draw_count(), 0..1);
}
}
fn aabb(&self) -> Aabb {
let local_aabb = self.geometry.aabb();
let corners = [
self.transform.transform_point3(local_aabb.min),
self.transform.transform_point3(glam::Vec3::new(
local_aabb.max.x,
local_aabb.min.y,
local_aabb.min.z,
)),
self.transform.transform_point3(glam::Vec3::new(
local_aabb.min.x,
local_aabb.max.y,
local_aabb.min.z,
)),
self.transform.transform_point3(glam::Vec3::new(
local_aabb.min.x,
local_aabb.min.y,
local_aabb.max.z,
)),
self.transform.transform_point3(glam::Vec3::new(
local_aabb.max.x,
local_aabb.max.y,
local_aabb.min.z,
)),
self.transform.transform_point3(glam::Vec3::new(
local_aabb.max.x,
local_aabb.min.y,
local_aabb.max.z,
)),
self.transform.transform_point3(glam::Vec3::new(
local_aabb.min.x,
local_aabb.max.y,
local_aabb.max.z,
)),
self.transform.transform_point3(local_aabb.max),
];
Aabb::from_points(corners)
}
fn transform(&self) -> Mat4 {
self.transform
}
fn set_transform(&mut self, transform: Mat4) {
self.transform = transform;
}
}