613 lines
19 KiB
Rust
613 lines
19 KiB
Rust
use crate::rbx::{RobloxPartDescription,RobloxWedgeDescription,RobloxCornerWedgeDescription};
|
|
use strafesnet_common::model::{Color4,TextureCoordinate,Mesh,MeshBuilder,IndexedGraphicsGroup,IndexedPhysicsGroup,IndexedVertex,PolygonGroupId,PolygonGroup,PolygonList,PositionId,TextureCoordinateId,NormalId,ColorId,VertexId,RenderConfigId};
|
|
use strafesnet_common::integer::{vec3,Planar64,Planar64Vec3};
|
|
|
|
#[derive(Debug)]
|
|
pub enum Primitives{
|
|
Sphere,
|
|
Cube,
|
|
Cylinder,
|
|
Wedge,
|
|
CornerWedge,
|
|
}
|
|
#[derive(Debug)]
|
|
pub struct PrimitivesError;
|
|
impl TryFrom<u32> for Primitives{
|
|
type Error=PrimitivesError;
|
|
fn try_from(value:u32)->Result<Self,Self::Error>{
|
|
match value{
|
|
0=>Ok(Primitives::Sphere),
|
|
1=>Ok(Primitives::Cube),
|
|
2=>Ok(Primitives::Cylinder),
|
|
3=>Ok(Primitives::Wedge),
|
|
4=>Ok(Primitives::CornerWedge),
|
|
_=>Err(PrimitivesError),
|
|
}
|
|
}
|
|
}
|
|
#[derive(Clone,Copy,Hash,PartialEq,Eq)]
|
|
pub enum CubeFace{
|
|
Right,
|
|
Top,
|
|
Back,
|
|
Left,
|
|
Bottom,
|
|
Front,
|
|
}
|
|
#[derive(Debug)]
|
|
pub struct CubeFaceError;
|
|
impl TryFrom<u32> for CubeFace{
|
|
type Error=CubeFaceError;
|
|
fn try_from(value:u32)->Result<Self,Self::Error>{
|
|
match value{
|
|
0=>Ok(CubeFace::Right),
|
|
1=>Ok(CubeFace::Top),
|
|
2=>Ok(CubeFace::Back),
|
|
3=>Ok(CubeFace::Left),
|
|
4=>Ok(CubeFace::Bottom),
|
|
5=>Ok(CubeFace::Front),
|
|
_=>Err(CubeFaceError),
|
|
}
|
|
}
|
|
}
|
|
const CUBE_DEFAULT_TEXTURE_COORDS:[TextureCoordinate;4]=[
|
|
TextureCoordinate::new(0.0,0.0),
|
|
TextureCoordinate::new(1.0,0.0),
|
|
TextureCoordinate::new(1.0,1.0),
|
|
TextureCoordinate::new(0.0,1.0),
|
|
];
|
|
const CUBE_DEFAULT_VERTICES:[Planar64Vec3;8]=[
|
|
vec3::int(-1,-1, 1),//0 left bottom back
|
|
vec3::int( 1,-1, 1),//1 right bottom back
|
|
vec3::int( 1, 1, 1),//2 right top back
|
|
vec3::int(-1, 1, 1),//3 left top back
|
|
vec3::int(-1, 1,-1),//4 left top front
|
|
vec3::int( 1, 1,-1),//5 right top front
|
|
vec3::int( 1,-1,-1),//6 right bottom front
|
|
vec3::int(-1,-1,-1),//7 left bottom front
|
|
];
|
|
const CUBE_DEFAULT_NORMALS:[Planar64Vec3;6]=[
|
|
vec3::int( 1, 0, 0),//CubeFace::Right
|
|
vec3::int( 0, 1, 0),//CubeFace::Top
|
|
vec3::int( 0, 0, 1),//CubeFace::Back
|
|
vec3::int(-1, 0, 0),//CubeFace::Left
|
|
vec3::int( 0,-1, 0),//CubeFace::Bottom
|
|
vec3::int( 0, 0,-1),//CubeFace::Front
|
|
];
|
|
|
|
pub struct CubeFaceDescription([FaceDescription;Self::FACES]);
|
|
impl CubeFaceDescription{
|
|
pub const FACES:usize=6;
|
|
pub fn new(RobloxPartDescription(part_description):RobloxPartDescription,textureless_render_id:RenderConfigId)->Self{
|
|
Self(part_description.map(|face_description|match face_description{
|
|
Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(),
|
|
None=>FaceDescription::new_with_render_id(textureless_render_id),
|
|
}))
|
|
}
|
|
}
|
|
pub struct WedgeFaceDescription([FaceDescription;Self::FACES]);
|
|
impl WedgeFaceDescription{
|
|
pub const FACES:usize=5;
|
|
pub fn new(RobloxWedgeDescription(part_description):RobloxWedgeDescription,textureless_render_id:RenderConfigId)->Self{
|
|
Self(part_description.map(|face_description|match face_description{
|
|
Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(),
|
|
None=>FaceDescription::new_with_render_id(textureless_render_id),
|
|
}))
|
|
}
|
|
}
|
|
pub struct CornerWedgeFaceDescription([FaceDescription;Self::FACES]);
|
|
impl CornerWedgeFaceDescription{
|
|
pub const FACES:usize=5;
|
|
pub fn new(RobloxCornerWedgeDescription(part_description):RobloxCornerWedgeDescription,textureless_render_id:RenderConfigId)->Self{
|
|
Self(part_description.map(|face_description|match face_description{
|
|
Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(),
|
|
None=>FaceDescription::new_with_render_id(textureless_render_id),
|
|
}))
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct FaceDescription{
|
|
pub render:RenderConfigId,
|
|
pub transform:glam::Affine2,
|
|
pub color:Color4,
|
|
}
|
|
impl FaceDescription{
|
|
pub fn new_with_render_id(render:RenderConfigId)->Self{
|
|
Self{
|
|
render,
|
|
transform:glam::Affine2::IDENTITY,
|
|
color:Color4::new(1.0,1.0,1.0,0.0),//zero alpha to hide the default texture
|
|
}
|
|
}
|
|
}
|
|
pub fn unit_cube(CubeFaceDescription(face_descriptions):CubeFaceDescription)->Mesh{
|
|
const CUBE_DEFAULT_POLYS:[[[u32;2];4];6]=[
|
|
// right (1, 0, 0)
|
|
[
|
|
[6,2],//[vertex,tex]
|
|
[5,1],
|
|
[2,0],
|
|
[1,3],
|
|
],
|
|
// top (0, 1, 0)
|
|
[
|
|
[5,3],
|
|
[4,2],
|
|
[3,1],
|
|
[2,0],
|
|
],
|
|
// back (0, 0, 1)
|
|
[
|
|
[0,3],
|
|
[1,2],
|
|
[2,1],
|
|
[3,0],
|
|
],
|
|
// left (-1, 0, 0)
|
|
[
|
|
[0,2],
|
|
[3,1],
|
|
[4,0],
|
|
[7,3],
|
|
],
|
|
// bottom (0,-1, 0)
|
|
[
|
|
[1,1],
|
|
[0,0],
|
|
[7,3],
|
|
[6,2],
|
|
],
|
|
// front (0, 0,-1)
|
|
[
|
|
[4,1],
|
|
[5,0],
|
|
[6,3],
|
|
[7,2],
|
|
],
|
|
];
|
|
let mut generated_pos=Vec::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 polygon_groups=Vec::new();
|
|
let mut graphics_groups=Vec::new();
|
|
let mut physics_group=IndexedPhysicsGroup::default();
|
|
let mut transforms=Vec::new();
|
|
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
|
|
for (face_id,face_description) in face_descriptions.into_iter().enumerate(){
|
|
//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){
|
|
transform_index
|
|
}else{
|
|
//create new transform_index
|
|
let transform_index=transforms.len();
|
|
transforms.push(face_description.transform);
|
|
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex|
|
|
face_description.transform.transform_point2(tex)
|
|
));
|
|
transform_index
|
|
} as u32;
|
|
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){
|
|
color_index
|
|
}else{
|
|
//create new color_index
|
|
let color_index=generated_color.len();
|
|
generated_color.push(face_description.color);
|
|
color_index
|
|
} as u32;
|
|
//always push normal
|
|
let normal_index=generated_normal.len() as u32;
|
|
generated_normal.push(CUBE_DEFAULT_NORMALS[face_id]);
|
|
//push vertices as they are needed
|
|
let group_id=PolygonGroupId::new(polygon_groups.len() as u32);
|
|
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![
|
|
CUBE_DEFAULT_POLYS[face_id].map(|[pos_id,tex_id]|{
|
|
let pos=CUBE_DEFAULT_VERTICES[pos_id 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:PositionId::new(pos_index),
|
|
tex:TextureCoordinateId::new(tex_id+4*transform_index),
|
|
normal:NormalId::new(normal_index),
|
|
color:ColorId::new(color_index),
|
|
};
|
|
let vert_index=generated_vertices.len();
|
|
generated_vertices.push(vertex);
|
|
VertexId::new(vert_index as u32)
|
|
}).to_vec(),
|
|
])));
|
|
graphics_groups.push(IndexedGraphicsGroup{
|
|
render:face_description.render,
|
|
groups:vec![group_id],
|
|
});
|
|
physics_group.groups.push(group_id);
|
|
}
|
|
Mesh{
|
|
unique_pos:generated_pos,
|
|
unique_tex:generated_tex,
|
|
unique_normal:generated_normal,
|
|
unique_color:generated_color,
|
|
unique_vertices:generated_vertices,
|
|
polygon_groups,
|
|
graphics_groups,
|
|
physics_groups:vec![physics_group],
|
|
}
|
|
}
|
|
//don't think too hard about the copy paste because this is all going into the map tool eventually...
|
|
pub fn unit_wedge(WedgeFaceDescription(face_descriptions):WedgeFaceDescription)->Mesh{
|
|
const WEDGE_DEFAULT_POLYS:[&[[u32;2]];5]=[
|
|
// right (1, 0, 0)
|
|
&[
|
|
[6,2],//[vertex,tex]
|
|
[2,0],
|
|
[1,3],
|
|
],
|
|
// FrontTop (0, 1, -1)
|
|
&[
|
|
[3,1],
|
|
[2,0],
|
|
[6,3],
|
|
[7,2],
|
|
],
|
|
// back (0, 0, 1)
|
|
&[
|
|
[0,3],
|
|
[1,2],
|
|
[2,1],
|
|
[3,0],
|
|
],
|
|
// left (-1, 0, 0)
|
|
&[
|
|
[0,2],
|
|
[3,1],
|
|
[7,3],
|
|
],
|
|
// bottom (0,-1, 0)
|
|
&[
|
|
[1,1],
|
|
[0,0],
|
|
[7,3],
|
|
[6,2],
|
|
],
|
|
];
|
|
const WEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[
|
|
vec3::int( 1, 0, 0),//Wedge::Right
|
|
vec3::int( 0, 1,-1),//Wedge::TopFront
|
|
vec3::int( 0, 0, 1),//Wedge::Back
|
|
vec3::int(-1, 0, 0),//Wedge::Left
|
|
vec3::int( 0,-1, 0),//Wedge::Bottom
|
|
];
|
|
let mut generated_pos=Vec::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 polygon_groups=Vec::new();
|
|
let mut graphics_groups=Vec::new();
|
|
let mut physics_group=IndexedPhysicsGroup::default();
|
|
let mut transforms=Vec::new();
|
|
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
|
|
for (face_id,face_description) in face_descriptions.into_iter().enumerate(){
|
|
//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){
|
|
transform_index
|
|
}else{
|
|
//create new transform_index
|
|
let transform_index=transforms.len();
|
|
transforms.push(face_description.transform);
|
|
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex|
|
|
face_description.transform.transform_point2(tex)
|
|
));
|
|
transform_index
|
|
} as u32;
|
|
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){
|
|
color_index
|
|
}else{
|
|
//create new color_index
|
|
let color_index=generated_color.len();
|
|
generated_color.push(face_description.color);
|
|
color_index
|
|
} as u32;
|
|
//always push normal
|
|
let normal_index=generated_normal.len() as u32;
|
|
generated_normal.push(WEDGE_DEFAULT_NORMALS[face_id]);
|
|
//push vertices as they are needed
|
|
let group_id=PolygonGroupId::new(polygon_groups.len() as u32);
|
|
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![
|
|
WEDGE_DEFAULT_POLYS[face_id].iter().map(|&[pos_id,tex_id]|{
|
|
let pos=CUBE_DEFAULT_VERTICES[pos_id 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:PositionId::new(pos_index),
|
|
tex:TextureCoordinateId::new(tex_id+4*transform_index),
|
|
normal:NormalId::new(normal_index),
|
|
color:ColorId::new(color_index),
|
|
};
|
|
let vert_index=generated_vertices.len();
|
|
generated_vertices.push(vertex);
|
|
VertexId::new(vert_index as u32)
|
|
}).collect()
|
|
])));
|
|
graphics_groups.push(IndexedGraphicsGroup{
|
|
render:face_description.render,
|
|
groups:vec![group_id],
|
|
});
|
|
physics_group.groups.push(group_id);
|
|
}
|
|
Mesh{
|
|
unique_pos:generated_pos,
|
|
unique_tex:generated_tex,
|
|
unique_normal:generated_normal,
|
|
unique_color:generated_color,
|
|
unique_vertices:generated_vertices,
|
|
polygon_groups,
|
|
graphics_groups,
|
|
physics_groups:vec![physics_group],
|
|
}
|
|
}
|
|
|
|
pub fn unit_cornerwedge(CornerWedgeFaceDescription(face_descriptions):CornerWedgeFaceDescription)->Mesh{
|
|
const CORNERWEDGE_DEFAULT_POLYS:[&[[u32;2]];5]=[
|
|
// right (1, 0, 0)
|
|
&[
|
|
[6,2],//[vertex,tex]
|
|
[5,1],
|
|
[1,3],
|
|
],
|
|
// BackTop (0, 1, 1)
|
|
&[
|
|
[5,3],
|
|
[0,1],
|
|
[1,0],
|
|
],
|
|
// LeftTop (-1, 1, 0)
|
|
&[
|
|
[5,3],
|
|
[7,2],
|
|
[0,1],
|
|
],
|
|
// bottom (0,-1, 0)
|
|
&[
|
|
[1,1],
|
|
[0,0],
|
|
[7,3],
|
|
[6,2],
|
|
],
|
|
// front (0, 0,-1)
|
|
&[
|
|
[5,0],
|
|
[6,3],
|
|
[7,2],
|
|
],
|
|
];
|
|
const CORNERWEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[
|
|
vec3::int( 1, 0, 0),//CornerWedge::Right
|
|
vec3::int( 0, 1, 1),//CornerWedge::BackTop
|
|
vec3::int(-1, 1, 0),//CornerWedge::LeftTop
|
|
vec3::int( 0,-1, 0),//CornerWedge::Bottom
|
|
vec3::int( 0, 0,-1),//CornerWedge::Front
|
|
];
|
|
let mut generated_pos=Vec::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 polygon_groups=Vec::new();
|
|
let mut graphics_groups=Vec::new();
|
|
let mut physics_group=IndexedPhysicsGroup::default();
|
|
let mut transforms=Vec::new();
|
|
//note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices.
|
|
for (face_id,face_description) in face_descriptions.into_iter().enumerate(){
|
|
//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){
|
|
transform_index
|
|
}else{
|
|
//create new transform_index
|
|
let transform_index=transforms.len();
|
|
transforms.push(face_description.transform);
|
|
generated_tex.extend(CUBE_DEFAULT_TEXTURE_COORDS.map(|tex|
|
|
face_description.transform.transform_point2(tex)
|
|
));
|
|
transform_index
|
|
} as u32;
|
|
let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){
|
|
color_index
|
|
}else{
|
|
//create new color_index
|
|
let color_index=generated_color.len();
|
|
generated_color.push(face_description.color);
|
|
color_index
|
|
} as u32;
|
|
//always push normal
|
|
let normal_index=generated_normal.len() as u32;
|
|
generated_normal.push(CORNERWEDGE_DEFAULT_NORMALS[face_id]);
|
|
//push vertices as they are needed
|
|
let group_id=PolygonGroupId::new(polygon_groups.len() as u32);
|
|
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(vec![
|
|
CORNERWEDGE_DEFAULT_POLYS[face_id].iter().map(|&[pos_id,tex_id]|{
|
|
let pos=CUBE_DEFAULT_VERTICES[pos_id 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:PositionId::new(pos_index),
|
|
tex:TextureCoordinateId::new(tex_id+4*transform_index),
|
|
normal:NormalId::new(normal_index),
|
|
color:ColorId::new(color_index),
|
|
};
|
|
let vert_index=generated_vertices.len();
|
|
generated_vertices.push(vertex);
|
|
VertexId::new(vert_index as u32)
|
|
}).collect(),
|
|
])));
|
|
graphics_groups.push(IndexedGraphicsGroup{
|
|
render:face_description.render,
|
|
groups:vec![group_id],
|
|
});
|
|
physics_group.groups.push(group_id);
|
|
}
|
|
Mesh{
|
|
unique_pos:generated_pos,
|
|
unique_tex:generated_tex,
|
|
unique_normal:generated_normal,
|
|
unique_color:generated_color,
|
|
unique_vertices:generated_vertices,
|
|
polygon_groups,
|
|
graphics_groups,
|
|
physics_groups:vec![physics_group],
|
|
}
|
|
}
|
|
|
|
// TODO: fix face texture orientation
|
|
pub fn unit_cylinder(face_descriptions:CubeFaceDescription)->Mesh{
|
|
// cylinder is oriented about the x axis
|
|
// roblox cylinders use projected grid coordinates
|
|
/// how many grid coordinates to use (positive and negative)
|
|
const GON:i32=3;
|
|
/// grid perimeter
|
|
const POINTS:[[i32;2];4*2*GON as usize]=const{
|
|
let mut points=[[0;2];{4*2*GON as usize}];
|
|
let mut i=-GON;
|
|
while i<GON{
|
|
points[(i+GON) as usize]=[i,GON];
|
|
points[(i+GON+1*2*GON) as usize]=[GON,-i];
|
|
points[(i+GON+2*2*GON) as usize]=[-i,-GON];
|
|
points[(i+GON+3*2*GON) as usize]=[-GON,i];
|
|
i+=1;
|
|
}
|
|
points
|
|
};
|
|
|
|
let mut mb=MeshBuilder::new();
|
|
let mut polygon_groups=Vec::with_capacity(CubeFaceDescription::FACES);
|
|
let mut graphics_groups=Vec::with_capacity(CubeFaceDescription::FACES);
|
|
let mut physics_group=IndexedPhysicsGroup{groups:Vec::with_capacity(CubeFaceDescription::FACES)};
|
|
let CubeFaceDescription([right,top,back,left,bottom,front])=face_descriptions;
|
|
|
|
macro_rules! end_face{
|
|
($face_description:expr,$end:expr,$iter:expr)=>{
|
|
let normal=mb.acquire_normal_id($end);
|
|
let color=mb.acquire_color_id($face_description.color);
|
|
|
|
// single polygon for physics
|
|
let polygon:Vec<_>=$iter.map(|[x,y]|{
|
|
let tex=mb.acquire_tex_id(
|
|
$face_description.transform.transform_point2(
|
|
(glam::vec2(-x as f32,y as f32).normalize()+1.0)/2.0
|
|
)
|
|
);
|
|
let pos=mb.acquire_pos_id($end+vec3::int(0,-x,y).with_length(Planar64::ONE).divide().wrap_1());
|
|
mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color})
|
|
}).collect();
|
|
|
|
// fanned polygons for graphics
|
|
let pos=mb.acquire_pos_id($end);
|
|
let tex=mb.acquire_tex_id($face_description.transform.transform_point2(glam::Vec2::ONE/2.0));
|
|
let center=mb.acquire_vertex_id(IndexedVertex{pos,tex,normal,color});
|
|
let polygon_list=(0..POINTS.len()).map(|i|
|
|
vec![center,polygon[i],polygon[(i+1)%POINTS.len()]]
|
|
).collect();
|
|
|
|
// end face graphics
|
|
let group_id=PolygonGroupId::new(polygon_groups.len() as u32);
|
|
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(polygon_list)));
|
|
graphics_groups.push(IndexedGraphicsGroup{
|
|
render:$face_description.render,
|
|
groups:vec![group_id],
|
|
});
|
|
|
|
// end face physics
|
|
let polygon_list=vec![polygon];
|
|
|
|
let group_id=PolygonGroupId::new(polygon_groups.len() as u32);
|
|
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(polygon_list)));
|
|
physics_group.groups.push(group_id);
|
|
}
|
|
}
|
|
macro_rules! tex{
|
|
($face_description:expr,$tex:expr)=>{{
|
|
let [x,y]=$tex;
|
|
$face_description.transform.transform_point2(
|
|
glam::vec2((x+GON) as f32,(y+GON) as f32)/(2*GON) as f32
|
|
)
|
|
}};
|
|
}
|
|
macro_rules! barrel_face{
|
|
($face_description:expr,$loop:ident,$lo_dir:expr,$hi_dir:expr,$tex_0:expr,$tex_1:expr,$tex_2:expr,$tex_3:expr)=>{
|
|
let mut polygon_list=Vec::with_capacity(CubeFaceDescription::FACES);
|
|
for $loop in -GON..GON{
|
|
// lo Z
|
|
let lz_dir=$lo_dir.with_length(Planar64::ONE).divide().wrap_1();
|
|
// hi Z
|
|
let hz_dir=$hi_dir.with_length(Planar64::ONE).divide().wrap_1();
|
|
|
|
// pos
|
|
let lx_lz_pos=mb.acquire_pos_id(vec3::NEG_X+lz_dir);
|
|
let lx_hz_pos=mb.acquire_pos_id(vec3::NEG_X+hz_dir);
|
|
let hx_hz_pos=mb.acquire_pos_id(vec3::X+hz_dir);
|
|
let hx_lz_pos=mb.acquire_pos_id(vec3::X+lz_dir);
|
|
// tex
|
|
let lx_lz_tex=mb.acquire_tex_id(tex!($face_description,$tex_0));
|
|
let lx_hz_tex=mb.acquire_tex_id(tex!($face_description,$tex_1));
|
|
let hx_hz_tex=mb.acquire_tex_id(tex!($face_description,$tex_2));
|
|
let hx_lz_tex=mb.acquire_tex_id(tex!($face_description,$tex_3));
|
|
// norm
|
|
let lz_norm=mb.acquire_normal_id(lz_dir);
|
|
let hz_norm=mb.acquire_normal_id(hz_dir);
|
|
// color
|
|
let color=mb.acquire_color_id($face_description.color);
|
|
|
|
polygon_list.push(vec![
|
|
mb.acquire_vertex_id(IndexedVertex{pos:lx_lz_pos,tex:lx_lz_tex,normal:lz_norm,color}),
|
|
mb.acquire_vertex_id(IndexedVertex{pos:lx_hz_pos,tex:lx_hz_tex,normal:hz_norm,color}),
|
|
mb.acquire_vertex_id(IndexedVertex{pos:hx_hz_pos,tex:hx_hz_tex,normal:hz_norm,color}),
|
|
mb.acquire_vertex_id(IndexedVertex{pos:hx_lz_pos,tex:hx_lz_tex,normal:lz_norm,color}),
|
|
]);
|
|
}
|
|
|
|
// push face
|
|
let group_id=PolygonGroupId::new(polygon_groups.len() as u32);
|
|
polygon_groups.push(PolygonGroup::PolygonList(PolygonList::new(polygon_list)));
|
|
graphics_groups.push(IndexedGraphicsGroup{
|
|
render:$face_description.render,
|
|
groups:vec![group_id],
|
|
});
|
|
physics_group.groups.push(group_id);
|
|
};
|
|
}
|
|
|
|
end_face!(right, vec3::X,POINTS.into_iter());
|
|
barrel_face!(top, z,vec3::int(0,GON,z),vec3::int(0,GON,z+1), [GON,z],[GON,z+1],[-GON,z+1],[-GON,z]);
|
|
barrel_face!(back, y,vec3::int(0,y+1,GON),vec3::int(0,y,GON), [GON,y+1],[GON,y],[-GON,y],[-GON,y+1]);
|
|
end_face!(left, vec3::NEG_X,POINTS.into_iter().rev());
|
|
barrel_face!(bottom, z,vec3::int(0,-GON,z+1),vec3::int(0,-GON,z), [-GON,z+1],[-GON,z],[GON,z],[GON,z+1]);
|
|
barrel_face!(front, y,vec3::int(0,y,-GON),vec3::int(0,y+1,-GON), [-GON,y],[-GON,y+1],[GON,y+1],[GON,y]);
|
|
|
|
let physics_groups=vec![physics_group];
|
|
|
|
mb.build(polygon_groups,graphics_groups,physics_groups)
|
|
}
|