strafe-client/src/primitives.rs

172 lines
4.8 KiB
Rust
Raw Normal View History

2023-09-28 22:43:10 +00:00
use crate::model::{IndexedModel, IndexedPolygon, IndexedGroup, IndexedVertex};
2023-09-28 00:24:25 +00:00
const CUBE_DEFAULT_TEXTURE_COORDS:[[f32;2];4]=[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]];
const CUBE_DEFAULT_VERTICES:[[f32;3];8]=[
[-1.,-1., 1.],//0 left bottom back
[ 1.,-1., 1.],//1 right bottom back
[ 1., 1., 1.],//2 right top back
[-1., 1., 1.],//3 left top back
[-1., 1.,-1.],//4 left top front
[ 1., 1.,-1.],//5 right top front
[ 1.,-1.,-1.],//6 right bottom front
[-1.,-1.,-1.],//7 left bottom front
];
const CUBE_DEFAULT_NORMALS:[[f32;3];6]=[
[ 1., 0., 0.],//AabbFace::Right
[ 0., 1., 0.],//AabbFace::Top
[ 0., 0., 1.],//AabbFace::Back
[-1., 0., 0.],//AabbFace::Left
[ 0.,-1., 0.],//AabbFace::Bottom
[ 0., 0.,-1.],//AabbFace::Front
];
const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
// right (1, 0, 0)
[
2023-09-28 22:43:10 +00:00
[6,2,0],//[vertex,tex,norm]
2023-09-28 00:24:25 +00:00
[5,1,0],
[2,0,0],
[1,3,0],
],
// top (0, 1, 0)
[
[5,3,1],
[4,2,1],
[3,1,1],
[2,0,1],
],
// back (0, 0, 1)
[
[0,3,2],
[1,2,2],
[2,1,2],
[3,0,2],
],
// left (-1, 0, 0)
[
[0,2,3],
[3,1,3],
[4,0,3],
[7,3,3],
],
// bottom (0,-1, 0)
[
[1,1,4],
[0,0,4],
[7,3,4],
[6,2,4],
],
// front (0, 0,-1)
[
[4,1,5],
[5,0,5],
[6,3,5],
[7,2,5],
],
];
2023-09-28 22:43:10 +00:00
pub fn the_unit_cube_lol() -> crate::model::IndexedModel{
generate_partial_unit_cube([Some(FaceDescription::default());6])
}
2023-09-28 00:24:25 +00:00
2023-09-28 22:43:10 +00:00
#[derive(Copy,Clone)]
2023-09-28 00:24:25 +00:00
pub struct FaceDescription{
2023-09-28 22:43:10 +00:00
pub texture:Option<u32>,
pub transform:glam::Affine2,
pub color:glam::Vec4,
2023-09-28 00:24:25 +00:00
}
impl std::default::Default for FaceDescription{
fn default() -> Self {
Self{
2023-09-28 22:43:10 +00:00
texture:None,
2023-09-28 00:24:25 +00:00
transform:glam::Affine2::IDENTITY,
color:glam::vec4(1.0,1.0,1.0,0.0),//zero alpha to hide the default texture
2023-09-28 00:24:25 +00:00
}
}
}
impl FaceDescription{
2023-09-28 22:43:10 +00:00
pub fn new(texture:u32,transform:glam::Affine2,color:glam::Vec4)->Self{
Self{texture:Some(texture),transform,color}
}
pub fn from_texture(texture:u32)->Self{
Self{
texture:Some(texture),
transform:glam::Affine2::IDENTITY,
color:glam::Vec4::ONE,
}
2023-09-28 00:24:25 +00:00
}
}
2023-09-28 22:43:10 +00:00
//TODO: it's probably better to use a shared vertex buffer between all primitives and use indexed rendering instead of generating a unique vertex buffer for each primitive.
//implementation: put all roblox primitives into one model.groups
2023-09-28 22:43:10 +00:00
pub fn generate_partial_unit_cube(face_descriptions:[Option<FaceDescription>;6]) -> crate::model::IndexedModel{
let mut generated_pos=Vec::<[f32;3]>::new();
let mut generated_tex=Vec::new();
let mut generated_normal=Vec::new();
let mut generated_color=Vec::new();
let mut generated_vertices=Vec::new();
let mut groups=Vec::new();
2023-09-27 21:10:45 +00:00
let mut transforms=Vec::new();
2023-09-28 22:43:10 +00:00
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
for (i,maybe_face_description) in face_descriptions.iter().enumerate(){
if let Some(face_description)=maybe_face_description{
//assume that scanning short lists is faster than hashing.
let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){
2023-09-27 21:10:45 +00:00
transform_index
}else{
//create new transform_index
let transform_index=transforms.len();
2023-09-28 22:43:10 +00:00
transforms.push(face_description.transform);
for tex in CUBE_DEFAULT_TEXTURE_COORDS{
generated_tex.push(*face_description.transform.transform_point2(glam::Vec2::from_array(tex)).as_ref());
2023-09-27 21:10:45 +00:00
}
transform_index
2023-09-28 22:43:10 +00:00
} as u32;
let color_index=if let Some(color_index)=generated_color.iter().position(|color|color==face_description.color.as_ref()){
color_index
}else{
//create new color_index
let color_index=generated_color.len();
generated_color.push(*face_description.color.as_ref());
color_index
} as u32;
//always push normal
let normal_index=generated_normal.len() as u32;
generated_normal.push(CUBE_DEFAULT_NORMALS[i]);
//push vertices as they are needed
groups.push(IndexedGroup{
texture:face_description.texture,
polys:vec![IndexedPolygon{
vertices:CUBE_DEFAULT_POLYS[i].map(|tup|{
let pos=CUBE_DEFAULT_VERTICES[tup[0] as usize];
let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){
pos_index
}else{
//create new pos_index
let pos_index=generated_pos.len();
generated_pos.push(pos);
pos_index
} as u32;
//always push vertex
let vertex=IndexedVertex{
pos:pos_index,
tex:tup[1]+4*transform_index,
normal:normal_index,
color:color_index,
};
let vert_index=generated_vertices.len();
generated_vertices.push(vertex);
vert_index as u32
}).to_vec(),
}],
});
2023-09-28 00:24:25 +00:00
}
2023-09-23 02:41:27 +00:00
}
2023-09-28 22:43:10 +00:00
IndexedModel{
unique_pos:generated_pos,
unique_tex:generated_tex,
unique_normal:generated_normal,
unique_color:generated_color,
unique_vertices:generated_vertices,
groups,
instances:Vec::new(),
2023-09-28 00:24:25 +00:00
}
}