use crate::{
core::{
algebra::{Matrix4, Point3, Vector2, Vector3, Vector4},
hash_combine,
inspect::{Inspect, PropertyInfo},
math::TriangleDefinition,
parking_lot::Mutex,
pool::{ErasedHandle, Handle},
sparse::AtomicIndex,
visitor::{Visit, VisitResult, Visitor},
},
material::Material,
renderer::{cache::CacheEntry, framework},
scene::{
mesh::{
buffer::{
TriangleBuffer, VertexAttributeDescriptor, VertexAttributeUsage, VertexBuffer,
VertexFetchError, VertexReadTrait, VertexWriteTrait,
},
vertex::{OldVertex, StaticVertex},
},
node::Node,
},
utils::raw_mesh::{RawMesh, RawMeshBuilder},
};
use fxhash::FxHasher;
use std::{hash::Hasher, sync::Arc};
#[derive(Debug, Clone, Default)]
pub struct SurfaceData {
pub vertex_buffer: VertexBuffer,
pub geometry_buffer: TriangleBuffer,
is_procedural: bool,
pub(in crate) cache_entry: AtomicIndex<CacheEntry<framework::geometry_buffer::GeometryBuffer>>,
}
impl SurfaceData {
pub fn new(
vertex_buffer: VertexBuffer,
triangles: TriangleBuffer,
is_procedural: bool,
) -> Self {
Self {
vertex_buffer,
geometry_buffer: triangles,
is_procedural,
cache_entry: AtomicIndex::unassigned(),
}
}
pub fn transform_geometry(&mut self, transform: &Matrix4<f32>) -> Result<(), VertexFetchError> {
let normal_matrix = transform.try_inverse().unwrap_or_default().transpose();
let mut vertex_buffer_mut = self.vertex_buffer.modify();
for mut view in vertex_buffer_mut.iter_mut() {
let position = view.read_3_f32(VertexAttributeUsage::Position)?;
view.write_3_f32(
VertexAttributeUsage::Position,
transform.transform_point(&Point3::from(position)).coords,
)?;
let normal = view.read_3_f32(VertexAttributeUsage::Normal)?;
view.write_3_f32(
VertexAttributeUsage::Normal,
normal_matrix.transform_vector(&normal),
)?;
let tangent = view.read_4_f32(VertexAttributeUsage::Tangent)?;
let new_tangent = normal_matrix.transform_vector(&tangent.xyz());
view.write_4_f32(
VertexAttributeUsage::Tangent,
Vector4::new(new_tangent.x, new_tangent.y, new_tangent.z, tangent.w),
)?;
}
Ok(())
}
pub fn from_raw_mesh<T: Copy>(
raw: RawMesh<T>,
layout: &[VertexAttributeDescriptor],
is_procedural: bool,
) -> Self {
Self {
vertex_buffer: VertexBuffer::new(raw.vertices.len(), layout, raw.vertices).unwrap(),
geometry_buffer: TriangleBuffer::new(raw.triangles),
is_procedural,
cache_entry: AtomicIndex::unassigned(),
}
}
pub fn calculate_tangents(&mut self) -> Result<(), VertexFetchError> {
let mut tan1 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];
let mut tan2 = vec![Vector3::default(); self.vertex_buffer.vertex_count() as usize];
for triangle in self.geometry_buffer.iter() {
let i1 = triangle[0] as usize;
let i2 = triangle[1] as usize;
let i3 = triangle[2] as usize;
let view1 = &self.vertex_buffer.get(i1).unwrap();
let view2 = &self.vertex_buffer.get(i2).unwrap();
let view3 = &self.vertex_buffer.get(i3).unwrap();
let v1 = view1.read_3_f32(VertexAttributeUsage::Position)?;
let v2 = view2.read_3_f32(VertexAttributeUsage::Position)?;
let v3 = view3.read_3_f32(VertexAttributeUsage::Position)?;
let w1 = view1.read_3_f32(VertexAttributeUsage::TexCoord0)?;
let w2 = view2.read_3_f32(VertexAttributeUsage::TexCoord0)?;
let w3 = view3.read_3_f32(VertexAttributeUsage::TexCoord0)?;
let x1 = v2.x - v1.x;
let x2 = v3.x - v1.x;
let y1 = v2.y - v1.y;
let y2 = v3.y - v1.y;
let z1 = v2.z - v1.z;
let z2 = v3.z - v1.z;
let s1 = w2.x - w1.x;
let s2 = w3.x - w1.x;
let t1 = w2.y - w1.y;
let t2 = w3.y - w1.y;
let r = 1.0 / (s1 * t2 - s2 * t1);
let sdir = Vector3::new(
(t2 * x1 - t1 * x2) * r,
(t2 * y1 - t1 * y2) * r,
(t2 * z1 - t1 * z2) * r,
);
tan1[i1] += sdir;
tan1[i2] += sdir;
tan1[i3] += sdir;
let tdir = Vector3::new(
(s1 * x2 - s2 * x1) * r,
(s1 * y2 - s2 * y1) * r,
(s1 * z2 - s2 * z1) * r,
);
tan2[i1] += tdir;
tan2[i2] += tdir;
tan2[i3] += tdir;
}
let mut vertex_buffer_mut = self.vertex_buffer.modify();
for (mut view, (t1, t2)) in vertex_buffer_mut.iter_mut().zip(tan1.into_iter().zip(tan2)) {
let normal = view.read_3_f32(VertexAttributeUsage::Normal)?;
let tangent = (t1 - normal.scale(normal.dot(&t1)))
.try_normalize(f32::EPSILON)
.unwrap_or_else(|| Vector3::new(0.0, 1.0, 0.0));
let handedness = normal.cross(&t1).dot(&t2).signum();
view.write_4_f32(
VertexAttributeUsage::Tangent,
Vector4::new(tangent.x, tangent.y, tangent.z, handedness),
)?;
}
Ok(())
}
pub fn make_unit_xy_quad() -> Self {
let vertices = vec![
StaticVertex {
position: Vector3::default(),
normal: Vector3::z(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::x(),
normal: Vector3::z(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(1.0, 1.0, 0.0),
normal: Vector3::z(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::y(),
normal: Vector3::z(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
];
let triangles = vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
Self::new(
VertexBuffer::new(vertices.len(), StaticVertex::layout(), vertices).unwrap(),
TriangleBuffer::new(triangles),
true,
)
}
pub fn make_collapsed_xy_quad() -> Self {
let vertices = vec![
StaticVertex {
position: Vector3::default(),
normal: Vector3::z(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::default(),
normal: Vector3::z(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::default(),
normal: Vector3::z(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::default(),
normal: Vector3::z(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
];
let triangles = vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
Self::new(
VertexBuffer::new(vertices.len(), StaticVertex::layout(), vertices).unwrap(),
TriangleBuffer::new(triangles),
true,
)
}
pub fn make_quad(transform: &Matrix4<f32>) -> Self {
let vertices = vec![
StaticVertex {
position: Vector3::new(-0.5, 0.5, 0.0),
normal: -Vector3::z(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, 0.0),
normal: -Vector3::z(),
tex_coord: Vector2::new(0.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, 0.0),
normal: -Vector3::z(),
tex_coord: Vector2::new(0.0, 0.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, -0.5, 0.0),
normal: -Vector3::z(),
tex_coord: Vector2::new(1.0, 0.0),
tangent: Vector4::default(),
},
];
let mut data = Self::new(
VertexBuffer::new(vertices.len(), StaticVertex::layout(), vertices).unwrap(),
TriangleBuffer::new(vec![
TriangleDefinition([0, 1, 2]),
TriangleDefinition([0, 2, 3]),
]),
true,
);
data.calculate_tangents().unwrap();
data.transform_geometry(transform).unwrap();
data
}
pub fn calculate_normals(&mut self) -> Result<(), VertexFetchError> {
let mut vertex_buffer_mut = self.vertex_buffer.modify();
for triangle in self.geometry_buffer.iter() {
let ia = triangle[0] as usize;
let ib = triangle[1] as usize;
let ic = triangle[2] as usize;
let a = vertex_buffer_mut
.get(ia)
.unwrap()
.read_3_f32(VertexAttributeUsage::Position)?;
let b = vertex_buffer_mut
.get(ib)
.unwrap()
.read_3_f32(VertexAttributeUsage::Position)?;
let c = vertex_buffer_mut
.get(ic)
.unwrap()
.read_3_f32(VertexAttributeUsage::Position)?;
let normal = (b - a).cross(&(c - a)).normalize();
vertex_buffer_mut
.get_mut(ia)
.unwrap()
.write_3_f32(VertexAttributeUsage::Normal, normal)?;
vertex_buffer_mut
.get_mut(ib)
.unwrap()
.write_3_f32(VertexAttributeUsage::Normal, normal)?;
vertex_buffer_mut
.get_mut(ic)
.unwrap()
.write_3_f32(VertexAttributeUsage::Normal, normal)?;
}
Ok(())
}
pub fn make_sphere(slices: usize, stacks: usize, r: f32, transform: &Matrix4<f32>) -> Self {
let mut builder = RawMeshBuilder::<StaticVertex>::new(stacks * slices, stacks * slices * 3);
let d_theta = std::f32::consts::PI / slices as f32;
let d_phi = 2.0 * std::f32::consts::PI / stacks as f32;
let d_tc_y = 1.0 / stacks as f32;
let d_tc_x = 1.0 / slices as f32;
for i in 0..stacks {
for j in 0..slices {
let nj = j + 1;
let ni = i + 1;
let k0 = r * (d_theta * i as f32).sin();
let k1 = (d_phi * j as f32).cos();
let k2 = (d_phi * j as f32).sin();
let k3 = r * (d_theta * i as f32).cos();
let k4 = r * (d_theta * ni as f32).sin();
let k5 = (d_phi * nj as f32).cos();
let k6 = (d_phi * nj as f32).sin();
let k7 = r * (d_theta * ni as f32).cos();
if i != (stacks - 1) {
let v0 = Vector3::new(k0 * k1, k0 * k2, k3);
let t0 = Vector2::new(d_tc_x * j as f32, d_tc_y * i as f32);
let v1 = Vector3::new(k4 * k1, k4 * k2, k7);
let t1 = Vector2::new(d_tc_x * j as f32, d_tc_y * ni as f32);
let v2 = Vector3::new(k4 * k5, k4 * k6, k7);
let t2 = Vector2::new(d_tc_x * nj as f32, d_tc_y * ni as f32);
builder.insert(StaticVertex::from_pos_uv_normal(v0, t0, v0));
builder.insert(StaticVertex::from_pos_uv_normal(v1, t1, v1));
builder.insert(StaticVertex::from_pos_uv_normal(v2, t2, v2));
}
if i != 0 {
let v0 = Vector3::new(k4 * k5, k4 * k6, k7);
let t0 = Vector2::new(d_tc_x * nj as f32, d_tc_y * ni as f32);
let v1 = Vector3::new(k0 * k5, k0 * k6, k3);
let t1 = Vector2::new(d_tc_x * nj as f32, d_tc_y * i as f32);
let v2 = Vector3::new(k0 * k1, k0 * k2, k3);
let t2 = Vector2::new(d_tc_x * j as f32, d_tc_y * i as f32);
builder.insert(StaticVertex::from_pos_uv_normal(v0, t0, v0));
builder.insert(StaticVertex::from_pos_uv_normal(v1, t1, v1));
builder.insert(StaticVertex::from_pos_uv_normal(v2, t2, v2));
}
}
}
let mut data = Self::from_raw_mesh(builder.build(), StaticVertex::layout(), true);
data.calculate_tangents().unwrap();
data.transform_geometry(transform).unwrap();
data
}
pub fn make_cone(sides: usize, r: f32, h: f32, transform: &Matrix4<f32>) -> Self {
let mut builder = RawMeshBuilder::<StaticVertex>::new(3 * sides, 3 * sides);
let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
let d_theta = 1.0 / sides as f32;
for i in 0..sides {
let nx0 = (d_phi * i as f32).cos();
let ny0 = (d_phi * i as f32).sin();
let nx1 = (d_phi * (i + 1) as f32).cos();
let ny1 = (d_phi * (i + 1) as f32).sin();
let x0 = r * nx0;
let z0 = r * ny0;
let x1 = r * nx1;
let z1 = r * ny1;
let tx0 = d_theta * i as f32;
let tx1 = d_theta * (i + 1) as f32;
let (t_cap_y_curr, t_cap_x_curr) = (d_phi * i as f32).sin_cos();
let (t_cap_y_next, t_cap_x_next) = (d_phi * (i + 1) as f32).sin_cos();
let t_cap_x_curr = t_cap_x_curr * 0.5 + 0.5;
let t_cap_y_curr = t_cap_y_curr * 0.5 + 0.5;
let t_cap_x_next = t_cap_x_next * 0.5 + 0.5;
let t_cap_y_next = t_cap_y_next * 0.5 + 0.5;
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(0.0, 0.0, 0.0),
Vector2::new(0.5, 0.5),
Vector3::new(0.0, -1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x0, 0.0, z0),
Vector2::new(t_cap_x_curr, t_cap_y_curr),
Vector3::new(0.0, -1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x1, 0.0, z1),
Vector2::new(t_cap_x_next, t_cap_y_next),
Vector3::new(0.0, -1.0, 0.0),
));
let tip = Vector3::new(0.0, h, 0.0);
let v_curr = Vector3::new(x0, 0.0, z0);
let v_next = Vector3::new(x1, 0.0, z1);
let n_next = (tip - v_next).cross(&(v_next - v_curr));
let n_curr = (tip - v_curr).cross(&(v_next - v_curr));
builder.insert(StaticVertex::from_pos_uv_normal(
tip,
Vector2::new(0.5, 0.0),
n_curr,
));
builder.insert(StaticVertex::from_pos_uv_normal(
v_next,
Vector2::new(tx1, 1.0),
n_next,
));
builder.insert(StaticVertex::from_pos_uv_normal(
v_curr,
Vector2::new(tx0, 1.0),
n_curr,
));
}
let mut data = Self::from_raw_mesh(builder.build(), StaticVertex::layout(), true);
data.calculate_tangents().unwrap();
data.transform_geometry(transform).unwrap();
data
}
pub fn make_cylinder(
sides: usize,
r: f32,
h: f32,
caps: bool,
transform: &Matrix4<f32>,
) -> Self {
let mut builder = RawMeshBuilder::<StaticVertex>::new(3 * sides, 3 * sides);
let d_phi = 2.0 * std::f32::consts::PI / sides as f32;
let d_theta = 1.0 / sides as f32;
for i in 0..sides {
let nx0 = (d_phi * i as f32).cos();
let ny0 = (d_phi * i as f32).sin();
let nx1 = (d_phi * (i + 1) as f32).cos();
let ny1 = (d_phi * (i + 1) as f32).sin();
let x0 = r * nx0;
let z0 = r * ny0;
let x1 = r * nx1;
let z1 = r * ny1;
if caps {
let (t_cap_y_curr, t_cap_x_curr) = (d_phi * i as f32).sin_cos();
let (t_cap_y_next, t_cap_x_next) = (d_phi * (i + 1) as f32).sin_cos();
let t_cap_x_curr = t_cap_x_curr * 0.5 + 0.5;
let t_cap_y_curr = t_cap_y_curr * 0.5 + 0.5;
let t_cap_x_next = t_cap_x_next * 0.5 + 0.5;
let t_cap_y_next = t_cap_y_next * 0.5 + 0.5;
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x1, h, z1),
Vector2::new(t_cap_x_next, t_cap_y_next),
Vector3::new(0.0, 1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x0, h, z0),
Vector2::new(t_cap_x_curr, t_cap_y_curr),
Vector3::new(0.0, 1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(0.0, h, 0.0),
Vector2::new(0.5, 0.5),
Vector3::new(0.0, 1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x0, 0.0, z0),
Vector2::new(t_cap_x_curr, t_cap_y_curr),
Vector3::new(0.0, -1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x1, 0.0, z1),
Vector2::new(t_cap_x_next, t_cap_y_next),
Vector3::new(0.0, -1.0, 0.0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(0.0, 0.0, 0.0),
Vector2::new(0.5, 0.5),
Vector3::new(0.0, -1.0, 0.0),
));
}
let t_side_curr = d_theta * i as f32;
let t_side_next = d_theta * (i + 1) as f32;
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x0, 0.0, z0),
Vector2::new(t_side_curr, 0.0),
Vector3::new(x0, 0.0, z0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x0, h, z0),
Vector2::new(t_side_curr, 1.0),
Vector3::new(x0, 0.0, z0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x1, 0.0, z1),
Vector2::new(t_side_next, 0.0),
Vector3::new(x1, 0.0, z1),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x1, 0.0, z1),
Vector2::new(t_side_next, 0.0),
Vector3::new(x1, 0.0, z1),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x0, h, z0),
Vector2::new(t_side_curr, 1.0),
Vector3::new(x0, 0.0, z0),
));
builder.insert(StaticVertex::from_pos_uv_normal(
Vector3::new(x1, h, z1),
Vector2::new(t_side_next, 1.0),
Vector3::new(x1, 0.0, z1),
));
}
let mut data = Self::from_raw_mesh(builder.build(), StaticVertex::layout(), true);
data.calculate_tangents().unwrap();
data.transform_geometry(transform).unwrap();
data
}
pub fn make_cube(transform: Matrix4<f32>) -> Self {
let vertices = vec![
StaticVertex {
position: Vector3::new(-0.5, -0.5, 0.5),
normal: Vector3::z(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, 0.5, 0.5),
normal: Vector3::z(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, 0.5),
normal: Vector3::z(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, 0.5),
normal: Vector3::z(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, -0.5, -0.5),
normal: -Vector3::z(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, 0.5, -0.5),
normal: -Vector3::z(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, -0.5),
normal: -Vector3::z(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, -0.5),
normal: -Vector3::z(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, -0.5, -0.5),
normal: -Vector3::x(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, 0.5, -0.5),
normal: -Vector3::x(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, 0.5, 0.5),
normal: -Vector3::x(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, -0.5, 0.5),
normal: -Vector3::x(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, -0.5),
normal: Vector3::x(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, -0.5),
normal: Vector3::x(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, 0.5),
normal: Vector3::x(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, 0.5),
normal: Vector3::x(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, 0.5, 0.5),
normal: Vector3::y(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, 0.5, -0.5),
normal: Vector3::y(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, -0.5),
normal: Vector3::y(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, 0.5, 0.5),
normal: Vector3::y(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, -0.5, 0.5),
normal: -Vector3::y(),
tex_coord: Vector2::default(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(-0.5, -0.5, -0.5),
normal: -Vector3::y(),
tex_coord: Vector2::y(),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, -0.5),
normal: -Vector3::y(),
tex_coord: Vector2::new(1.0, 1.0),
tangent: Vector4::default(),
},
StaticVertex {
position: Vector3::new(0.5, -0.5, 0.5),
normal: -Vector3::y(),
tex_coord: Vector2::x(),
tangent: Vector4::default(),
},
];
let triangles = vec![
TriangleDefinition([2, 1, 0]),
TriangleDefinition([3, 2, 0]),
TriangleDefinition([4, 5, 6]),
TriangleDefinition([4, 6, 7]),
TriangleDefinition([10, 9, 8]),
TriangleDefinition([11, 10, 8]),
TriangleDefinition([12, 13, 14]),
TriangleDefinition([12, 14, 15]),
TriangleDefinition([18, 17, 16]),
TriangleDefinition([19, 18, 16]),
TriangleDefinition([20, 21, 22]),
TriangleDefinition([20, 22, 23]),
];
let mut data = Self::new(
VertexBuffer::new(vertices.len(), StaticVertex::layout(), vertices).unwrap(),
TriangleBuffer::new(triangles),
true,
);
data.calculate_tangents().unwrap();
data.transform_geometry(&transform).unwrap();
data
}
pub fn content_hash(&self) -> u64 {
hash_combine(
self.geometry_buffer.data_hash(),
self.vertex_buffer.data_hash(),
)
}
pub fn clear(&mut self) {
self.geometry_buffer.modify().clear();
self.vertex_buffer.modify().clear();
}
}
impl Visit for SurfaceData {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.is_procedural.visit("IsProcedural", visitor)?;
if self.is_procedural {
if self.vertex_buffer.visit("VertexBuffer", visitor).is_err() && visitor.is_reading() {
let mut old_vertices = Vec::<OldVertex>::new();
old_vertices.visit("Vertices", visitor)?;
self.vertex_buffer =
VertexBuffer::new(old_vertices.len(), OldVertex::layout(), old_vertices)
.unwrap();
};
if self
.geometry_buffer
.visit("GeometryBuffer", visitor)
.is_err()
&& visitor.is_reading()
{
let mut triangles = Vec::<TriangleDefinition>::new();
triangles.visit("Triangles", visitor)?;
self.geometry_buffer = TriangleBuffer::new(triangles);
}
}
visitor.leave_region()
}
}
#[derive(Copy, Clone, Debug)]
pub struct VertexWeight {
pub value: f32,
pub effector: ErasedHandle,
}
impl Default for VertexWeight {
fn default() -> Self {
Self {
value: 0.0,
effector: ErasedHandle::none(),
}
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct VertexWeightSet {
weights: [VertexWeight; 4],
count: usize,
}
impl VertexWeightSet {
pub fn push(&mut self, weight: VertexWeight) -> bool {
if self.count < self.weights.len() {
self.weights[self.count] = weight;
self.count += 1;
true
} else {
false
}
}
pub fn len(&self) -> usize {
self.count
}
pub fn is_empty(&self) -> bool {
self.count == 0
}
pub fn iter(&self) -> std::slice::Iter<VertexWeight> {
self.weights[0..self.count].iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<VertexWeight> {
self.weights[0..self.count].iter_mut()
}
pub fn normalize(&mut self) {
let len = self.iter().fold(0.0, |qs, w| qs + w.value * w.value).sqrt();
if len >= f32::EPSILON {
let k = 1.0 / len;
for w in self.iter_mut() {
w.value *= k;
}
}
}
}
#[derive(Debug, Clone, Inspect)]
pub struct Surface {
data: Option<Arc<Mutex<SurfaceData>>>,
material: Arc<Mutex<Material>>,
#[inspect(skip)]
pub vertex_weights: Vec<VertexWeightSet>,
pub bones: Vec<Handle<Node>>,
}
impl Default for Surface {
fn default() -> Self {
Self {
data: None,
material: Arc::new(Mutex::new(Material::standard())),
vertex_weights: Default::default(),
bones: Default::default(),
}
}
}
impl Surface {
#[inline]
pub fn new(data: Arc<Mutex<SurfaceData>>) -> Self {
Self {
data: Some(data),
..Default::default()
}
}
pub fn material_id(&self) -> u64 {
&*self.material as *const _ as u64
}
pub fn batch_id(&self) -> u64 {
let mut hasher = FxHasher::default();
hasher.write_u64(self.material_id());
hasher.write_u64(&**self.data.as_ref().unwrap() as *const _ as u64);
hasher.finish()
}
#[inline]
pub fn data(&self) -> Arc<Mutex<SurfaceData>> {
self.data.as_ref().unwrap().clone()
}
pub fn material(&self) -> &Arc<Mutex<Material>> {
&self.material
}
pub fn set_material(&mut self, material: Arc<Mutex<Material>>) {
self.material = material;
}
#[inline]
pub fn bones(&self) -> &[Handle<Node>] {
&self.bones
}
}
impl Visit for Surface {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.data.visit("Data", visitor)?;
self.bones.visit("Bones", visitor)?;
let _ = self.material.visit("Material", visitor);
visitor.leave_region()
}
}
pub struct SurfaceBuilder {
data: Arc<Mutex<SurfaceData>>,
material: Option<Arc<Mutex<Material>>>,
bones: Vec<Handle<Node>>,
}
impl SurfaceBuilder {
pub fn new(data: Arc<Mutex<SurfaceData>>) -> Self {
Self {
data,
material: None,
bones: Default::default(),
}
}
pub fn with_material(mut self, material: Arc<Mutex<Material>>) -> Self {
self.material = Some(material);
self
}
pub fn with_bones(mut self, bones: Vec<Handle<Node>>) -> Self {
self.bones = bones;
self
}
pub fn build(self) -> Surface {
Surface {
data: Some(self.data),
material: self
.material
.unwrap_or_else(|| Arc::new(Mutex::new(Material::standard()))),
vertex_weights: Default::default(),
bones: self.bones,
}
}
}