Compare commits
18 Commits
master
...
color-vert
Author | SHA1 | Date | |
---|---|---|---|
24acb46173 | |||
ff3b24fe73 | |||
d022549a76 | |||
ca1786029c | |||
4294ca6360 | |||
c0e108455a | |||
c32d3ebd98 | |||
822c9d6d5f | |||
59ee0cee3b | |||
9dd4a48630 | |||
bd191c65a1 | |||
39861c526b | |||
531473ef83 | |||
b9c21b6e62 | |||
b233d497ad | |||
27c7b7b785 | |||
097dccc91e | |||
84b96960a6 |
26
src/body.rs
26
src/body.rs
@ -284,7 +284,7 @@ pub enum AabbFace{
|
|||||||
Bottom,
|
Bottom,
|
||||||
Front,
|
Front,
|
||||||
}
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Aabb {
|
pub struct Aabb {
|
||||||
min: glam::Vec3,
|
min: glam::Vec3,
|
||||||
max: glam::Vec3,
|
max: glam::Vec3,
|
||||||
@ -387,28 +387,30 @@ type TreyMesh = Aabb;
|
|||||||
pub struct ModelPhysics {
|
pub struct ModelPhysics {
|
||||||
//A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es
|
//A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es
|
||||||
//in this iteration, all it needs is extents.
|
//in this iteration, all it needs is extents.
|
||||||
model_transform: glam::Affine3A,
|
mesh: TreyMesh,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelPhysics {
|
impl ModelPhysics {
|
||||||
pub fn new(model_transform:glam::Affine3A) -> Self {
|
pub fn from_model(model:&crate::model::IndexedModel,model_transform:glam::Affine3A) -> Self {
|
||||||
Self{model_transform}
|
let mut aabb=Aabb::new();
|
||||||
|
for indexed_vertex in &model.unique_vertices {
|
||||||
|
aabb.grow(model_transform.transform_point3(glam::Vec3::from_array(model.unique_pos[indexed_vertex.pos as usize])));
|
||||||
|
}
|
||||||
|
Self{
|
||||||
|
mesh:aabb,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn unit_vertices(&self) -> [glam::Vec3;8] {
|
pub fn unit_vertices(&self) -> [glam::Vec3;8] {
|
||||||
Aabb::unit_vertices()
|
Aabb::unit_vertices()
|
||||||
}
|
}
|
||||||
pub fn mesh(&self) -> TreyMesh {
|
pub fn mesh(&self) -> &TreyMesh {
|
||||||
let mut aabb=Aabb::new();
|
return &self.mesh;
|
||||||
for &vertex in self.unit_vertices().iter() {
|
|
||||||
aabb.grow(self.model_transform.transform_point3(vertex));
|
|
||||||
}
|
|
||||||
return aabb;
|
|
||||||
}
|
}
|
||||||
pub fn unit_face_vertices(&self,face:TreyMeshFace) -> [glam::Vec3;4] {
|
pub fn unit_face_vertices(&self,face:TreyMeshFace) -> [glam::Vec3;4] {
|
||||||
Aabb::unit_face_vertices(face)
|
Aabb::unit_face_vertices(face)
|
||||||
}
|
}
|
||||||
pub fn face_mesh(&self,face:TreyMeshFace) -> TreyMesh {
|
pub fn face_mesh(&self,face:TreyMeshFace) -> TreyMesh {
|
||||||
let mut aabb=self.mesh();
|
let mut aabb=self.mesh.clone();
|
||||||
//in this implementation face = worldspace aabb face
|
//in this implementation face = worldspace aabb face
|
||||||
match face {
|
match face {
|
||||||
AabbFace::Right => aabb.min.x=aabb.max.x,
|
AabbFace::Right => aabb.min.x=aabb.max.x,
|
||||||
@ -435,7 +437,7 @@ pub struct RelativeCollision {
|
|||||||
|
|
||||||
impl RelativeCollision {
|
impl RelativeCollision {
|
||||||
pub fn mesh(&self,models:&Vec<ModelPhysics>) -> TreyMesh {
|
pub fn mesh(&self,models:&Vec<ModelPhysics>) -> TreyMesh {
|
||||||
return models.get(self.model as usize).unwrap().face_mesh(self.face)
|
return models.get(self.model as usize).unwrap().face_mesh(self.face).clone()
|
||||||
}
|
}
|
||||||
pub fn normal(&self,models:&Vec<ModelPhysics>) -> glam::Vec3 {
|
pub fn normal(&self,models:&Vec<ModelPhysics>) -> glam::Vec3 {
|
||||||
return models.get(self.model as usize).unwrap().face_normal(self.face)
|
return models.get(self.model as usize).unwrap().face_normal(self.face)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::model::{ModelData,ModelInstance};
|
use crate::model::{IndexedModelInstances,ModelInstance};
|
||||||
|
|
||||||
use crate::primitives;
|
use crate::primitives;
|
||||||
|
|
||||||
@ -70,46 +70,41 @@ impl std::hash::Hash for RobloxTextureTransform {
|
|||||||
self.scale_v.to_ne_bytes().hash(state);
|
self.scale_v.to_ne_bytes().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Hash)]
|
#[derive(Clone,PartialEq)]
|
||||||
struct PartFaceTextureDescription{
|
struct RobloxFaceTextureDescription{
|
||||||
texture:u32,
|
texture:u32,
|
||||||
|
color:glam::Vec4,
|
||||||
transform:RobloxTextureTransform,
|
transform:RobloxTextureTransform,
|
||||||
}
|
}
|
||||||
type PartTextureDescription=[Option<PartFaceTextureDescription>;6];
|
impl std::cmp::Eq for RobloxFaceTextureDescription{}//????
|
||||||
#[derive(Hash,Eq,PartialEq)]
|
impl std::hash::Hash for RobloxFaceTextureDescription {
|
||||||
struct RobloxUnitCubeGenerationData{
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
texture:Option<u32>,
|
self.texture.hash(state);
|
||||||
faces:[Option<RobloxTextureTransform>;6],
|
self.transform.hash(state);
|
||||||
}
|
for &el in self.color.as_ref().iter() {
|
||||||
impl std::default::Default for RobloxUnitCubeGenerationData{
|
el.to_ne_bytes().hash(state);
|
||||||
fn default() -> Self {
|
|
||||||
Self{
|
|
||||||
texture:None,
|
|
||||||
faces:[Some(RobloxTextureTransform::default());6],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl RobloxUnitCubeGenerationData{
|
type RobloxPartDescription=[Option<RobloxFaceTextureDescription>;6];
|
||||||
fn empty() -> Self {
|
//type RobloxWedgeDescription=[Option<RobloxFaceTextureDescription>;5];
|
||||||
Self{
|
#[derive(Clone,Eq,Hash,PartialEq)]
|
||||||
texture:None,
|
enum RobloxBasePartDescription{
|
||||||
faces:[None,None,None,None,None,None],
|
Part(RobloxPartDescription),
|
||||||
|
//Wedge(RobloxWedgeDescription),
|
||||||
}
|
}
|
||||||
}
|
pub fn generate_indexed_models_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(IndexedModelInstances,glam::Vec3), Box<dyn std::error::Error>>{
|
||||||
}
|
//IndexedModelInstances includes textures
|
||||||
pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<ModelData>,Vec<String>,glam::Vec3), Box<dyn std::error::Error>>{
|
|
||||||
//ModelData includes texture dds
|
|
||||||
let mut spawn_point=glam::Vec3::ZERO;
|
let mut spawn_point=glam::Vec3::ZERO;
|
||||||
|
|
||||||
//TODO: generate unit Block, Wedge, etc. after based on part shape lists
|
let mut indexed_models=Vec::new();
|
||||||
let mut modeldatas=Vec::new();
|
let mut model_id_from_description=std::collections::HashMap::<RobloxBasePartDescription,usize>::new();
|
||||||
|
|
||||||
let mut texture_id_from_asset_id=std::collections::HashMap::<u64,u32>::new();
|
let mut texture_id_from_asset_id=std::collections::HashMap::<u64,u32>::new();
|
||||||
let mut asset_id_from_texture_id=Vec::new();
|
let mut asset_id_from_texture_id=Vec::new();
|
||||||
|
|
||||||
let mut object_refs=Vec::new();
|
let mut object_refs=Vec::new();
|
||||||
let mut temp_objects=Vec::new();
|
let mut temp_objects=Vec::new();
|
||||||
let mut model_id_from_ucgd=std::collections::HashMap::<RobloxUnitCubeGenerationData,usize>::new();
|
|
||||||
recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart");
|
recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart");
|
||||||
for object_ref in object_refs {
|
for object_ref in object_refs {
|
||||||
if let Some(object)=dom.get_by_ref(object_ref){
|
if let Some(object)=dom.get_by_ref(object_ref){
|
||||||
@ -150,15 +145,19 @@ pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<Mode
|
|||||||
temp_objects.clear();
|
temp_objects.clear();
|
||||||
recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal");
|
recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal");
|
||||||
|
|
||||||
let mut part_texture_description:PartTextureDescription=[None,None,None,None,None,None];
|
let mut part_texture_description:RobloxPartDescription=[None,None,None,None,None,None];
|
||||||
for &decal_ref in &temp_objects{
|
for &decal_ref in &temp_objects{
|
||||||
if let Some(decal)=dom.get_by_ref(decal_ref){
|
if let Some(decal)=dom.get_by_ref(decal_ref){
|
||||||
if let (
|
if let (
|
||||||
Some(rbx_dom_weak::types::Variant::Content(content)),
|
Some(rbx_dom_weak::types::Variant::Content(content)),
|
||||||
Some(rbx_dom_weak::types::Variant::Enum(normalid)),
|
Some(rbx_dom_weak::types::Variant::Enum(normalid)),
|
||||||
|
Some(rbx_dom_weak::types::Variant::Color3(decal_color3)),
|
||||||
|
Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)),
|
||||||
) = (
|
) = (
|
||||||
decal.properties.get("Texture"),
|
decal.properties.get("Texture"),
|
||||||
decal.properties.get("Face"),
|
decal.properties.get("Face"),
|
||||||
|
decal.properties.get("Color3"),
|
||||||
|
decal.properties.get("Transparency"),
|
||||||
) {
|
) {
|
||||||
if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
|
if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
|
||||||
let texture_id=if let Some(&texture_id)=texture_id_from_asset_id.get(&asset_id.0){
|
let texture_id=if let Some(&texture_id)=texture_id_from_asset_id.get(&asset_id.0){
|
||||||
@ -172,6 +171,7 @@ pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<Mode
|
|||||||
let face=normalid.to_u32();
|
let face=normalid.to_u32();
|
||||||
if face<6{
|
if face<6{
|
||||||
let mut roblox_texture_transform=RobloxTextureTransform::default();
|
let mut roblox_texture_transform=RobloxTextureTransform::default();
|
||||||
|
let mut roblox_texture_color=glam::Vec4::ONE;
|
||||||
if decal.class=="Texture"{
|
if decal.class=="Texture"{
|
||||||
//generate tranform
|
//generate tranform
|
||||||
if let (
|
if let (
|
||||||
@ -199,11 +199,12 @@ pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<Mode
|
|||||||
offset_u:*ox/(*sx),offset_v:*oy/(*sy),
|
offset_u:*ox/(*sx),offset_v:*oy/(*sy),
|
||||||
scale_u:size_u/(*sx),scale_v:size_v/(*sy),
|
scale_u:size_u/(*sx),scale_v:size_v/(*sy),
|
||||||
};
|
};
|
||||||
|
roblox_texture_color=glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//I can alos put the color into here and generate the vertices with the color
|
part_texture_description[face as usize]=Some(RobloxFaceTextureDescription{
|
||||||
part_texture_description[face as usize]=Some(PartFaceTextureDescription{
|
|
||||||
texture:texture_id,
|
texture:texture_id,
|
||||||
|
color:roblox_texture_color,
|
||||||
transform:roblox_texture_transform,
|
transform:roblox_texture_transform,
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
@ -213,65 +214,49 @@ pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<Mode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut unit_cube_generation_data_list=Vec::new();
|
//TODO: generate unit Block, Wedge, etc. based on part shape lists
|
||||||
let mut unit_cube_from_texture_id=std::collections::HashMap::<u32,usize>::new();
|
let basepart_texture_description=RobloxBasePartDescription::Part(part_texture_description);
|
||||||
//use part_texture_description to extract unique texture faces
|
|
||||||
let mut add_negative_cube=false;
|
|
||||||
let mut negative_cube=RobloxUnitCubeGenerationData::empty();
|
|
||||||
for (i,maybe_part_face) in part_texture_description.iter().enumerate(){
|
|
||||||
if let Some(part_face)=maybe_part_face{
|
|
||||||
let unit_cube_id=if let Some(&unit_cube_id)=unit_cube_from_texture_id.get(&part_face.texture){
|
|
||||||
unit_cube_id
|
|
||||||
}else{
|
|
||||||
let unit_cube_id=unit_cube_generation_data_list.len();
|
|
||||||
unit_cube_generation_data_list.push(RobloxUnitCubeGenerationData::empty());
|
|
||||||
unit_cube_from_texture_id.insert(part_face.texture,unit_cube_id);
|
|
||||||
unit_cube_generation_data_list[unit_cube_id].texture=Some(part_face.texture);
|
|
||||||
unit_cube_id
|
|
||||||
};
|
|
||||||
unit_cube_generation_data_list[unit_cube_id].faces[i]=Some(part_face.transform);
|
|
||||||
}else{
|
|
||||||
add_negative_cube=true;
|
|
||||||
negative_cube.faces[i]=Some(RobloxTextureTransform::default());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//must add the rest of the cube to complete the faces!
|
|
||||||
if add_negative_cube{
|
|
||||||
unit_cube_generation_data_list.push(negative_cube);
|
|
||||||
}
|
|
||||||
for roblox_unit_cube_generation_data in unit_cube_generation_data_list.drain(..){
|
|
||||||
//make new model if unit cube has not been crated before
|
//make new model if unit cube has not been crated before
|
||||||
let model_id=if let Some(&model_id)=model_id_from_ucgd.get(&roblox_unit_cube_generation_data){
|
let model_id=if let Some(&model_id)=model_id_from_description.get(&basepart_texture_description){
|
||||||
//push to existing texture model
|
//push to existing texture model
|
||||||
model_id
|
model_id
|
||||||
}else{
|
}else{
|
||||||
let unit_cube_generation_data=roblox_unit_cube_generation_data.faces.map(|face|{
|
let model_id=indexed_models.len();
|
||||||
|
model_id_from_description.insert(basepart_texture_description.clone(),model_id);//borrow checker going crazy
|
||||||
|
match basepart_texture_description{
|
||||||
|
RobloxBasePartDescription::Part(part_texture_description)=>{
|
||||||
|
let unit_cube_faces=part_texture_description.map(|face|{
|
||||||
match face{
|
match face{
|
||||||
Some(roblox_texture_transform)=>Some(
|
Some(roblox_texture_transform)=>Some(
|
||||||
glam::Affine2::from_translation(
|
primitives::FaceDescription{
|
||||||
glam::vec2(roblox_texture_transform.offset_u,roblox_texture_transform.offset_v)
|
texture:Some(roblox_texture_transform.texture),
|
||||||
|
transform:glam::Affine2::from_translation(
|
||||||
|
glam::vec2(roblox_texture_transform.transform.offset_u,roblox_texture_transform.transform.offset_v)
|
||||||
)
|
)
|
||||||
*glam::Affine2::from_scale(
|
*glam::Affine2::from_scale(
|
||||||
glam::vec2(roblox_texture_transform.scale_u,roblox_texture_transform.scale_v)
|
glam::vec2(roblox_texture_transform.transform.scale_u,roblox_texture_transform.transform.scale_v)
|
||||||
)
|
|
||||||
),
|
),
|
||||||
None=>None,
|
color:roblox_texture_transform.color,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
None=>Some(primitives::FaceDescription::default()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let mut new_modeldatas=crate::model::generate_modeldatas(primitives::generate_partial_unit_cube(unit_cube_generation_data),ModelData::COLOR_FLOATS_WHITE);
|
let indexed_model=primitives::generate_partial_unit_cube(unit_cube_faces);
|
||||||
new_modeldatas[0].texture=roblox_unit_cube_generation_data.texture;
|
indexed_models.push(indexed_model);
|
||||||
let model_id=modeldatas.len();
|
|
||||||
modeldatas.append(&mut new_modeldatas);
|
|
||||||
model_id_from_ucgd.insert(roblox_unit_cube_generation_data,model_id);
|
|
||||||
model_id
|
model_id
|
||||||
|
},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
modeldatas[model_id].instances.push(ModelInstance {
|
indexed_models[model_id].instances.push(ModelInstance {
|
||||||
model_transform,
|
model_transform,
|
||||||
color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
color: glam::Vec4::ONE,//glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok((IndexedModelInstances{
|
||||||
Ok((modeldatas,asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(),spawn_point))
|
textures:asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(),
|
||||||
|
models:indexed_models,
|
||||||
|
},spawn_point))
|
||||||
}
|
}
|
||||||
|
183
src/main.rs
183
src/main.rs
@ -1,6 +1,6 @@
|
|||||||
use std::{borrow::Cow, time::Instant};
|
use std::{borrow::Cow, time::Instant};
|
||||||
use wgpu::{util::DeviceExt, AstcBlock, AstcChannel};
|
use wgpu::{util::DeviceExt, AstcBlock, AstcChannel};
|
||||||
use model::{Vertex,ModelData,ModelInstance};
|
use model::{Vertex,ModelInstance};
|
||||||
use body::{InputInstruction, PhysicsInstruction};
|
use body::{InputInstruction, PhysicsInstruction};
|
||||||
use instruction::{TimedInstruction, InstructionConsumer};
|
use instruction::{TimedInstruction, InstructionConsumer};
|
||||||
|
|
||||||
@ -83,20 +83,22 @@ impl GraphicsData {
|
|||||||
depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
|
depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_model_physics(&mut self,modeldatas:&Vec<ModelData>){
|
fn generate_model_physics(&mut self,indexed_models:&model::IndexedModelInstances){
|
||||||
self.physics.models.append(&mut modeldatas.iter().map(|m|
|
for model in &indexed_models.models{
|
||||||
//make aabb and run vertices to get realistic bounds
|
//make aabb and run vertices to get realistic bounds
|
||||||
m.instances.iter().map(|t|body::ModelPhysics::new(t.model_transform))
|
for model_instance in &model.instances{
|
||||||
).flatten().collect());
|
self.physics.models.push(body::ModelPhysics::from_model(&model,model_instance.model_transform));
|
||||||
|
}
|
||||||
|
}
|
||||||
println!("Physics Objects: {}",self.physics.models.len());
|
println!("Physics Objects: {}",self.physics.models.len());
|
||||||
}
|
}
|
||||||
fn generate_model_graphics(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,mut modeldatas:Vec<ModelData>,textures:Vec<String>){
|
fn generate_model_graphics(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,mut indexed_models:model::IndexedModelInstances){
|
||||||
//generate texture view per texture
|
//generate texture view per texture
|
||||||
|
|
||||||
//idk how to do this gooder lol
|
//idk how to do this gooder lol
|
||||||
let mut double_map=std::collections::HashMap::<u32,u32>::new();
|
let mut double_map=std::collections::HashMap::<u32,u32>::new();
|
||||||
let mut texture_views:Vec<wgpu::TextureView>=Vec::with_capacity(textures.len());
|
let mut texture_views:Vec<wgpu::TextureView>=Vec::with_capacity(indexed_models.textures.len());
|
||||||
for (i,t) in textures.iter().enumerate(){
|
for (i,t) in indexed_models.textures.iter().enumerate(){
|
||||||
if let Ok(mut file) = std::fs::File::open(std::path::Path::new(&format!("textures/{}.dds",t))){
|
if let Ok(mut file) = std::fs::File::open(std::path::Path::new(&format!("textures/{}.dds",t))){
|
||||||
let image = ddsfile::Dds::read(&mut file).unwrap();
|
let image = ddsfile::Dds::read(&mut file).unwrap();
|
||||||
|
|
||||||
@ -135,22 +137,92 @@ impl GraphicsData {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//de-index models and split groups with different textures into separate models
|
||||||
|
//the models received here are supposed to be tightly packed, i.e. no code needs to check if two models are using the same groups.
|
||||||
|
let mut unique_texture_models=Vec::with_capacity(indexed_models.models.len());
|
||||||
|
for mut model in indexed_models.models.drain(..){
|
||||||
|
//check each group, if it's using a new texture then make a new clone of the model
|
||||||
|
let id=unique_texture_models.len();
|
||||||
|
let mut unique_textures=Vec::new();
|
||||||
|
for group in model.groups.drain(..){
|
||||||
|
//ignore zero coppy optimization for now
|
||||||
|
let texture_index=if let Some(texture_index)=unique_textures.iter().position(|&texture|texture==group.texture){
|
||||||
|
texture_index
|
||||||
|
}else{
|
||||||
|
//create new texture_index
|
||||||
|
let texture_index=unique_textures.len();
|
||||||
|
unique_textures.push(group.texture);
|
||||||
|
unique_texture_models.push(model::IndexedModelSingleTexture{
|
||||||
|
unique_pos:model.unique_pos.clone(),
|
||||||
|
unique_tex:model.unique_tex.clone(),
|
||||||
|
unique_normal:model.unique_normal.clone(),
|
||||||
|
unique_color:model.unique_color.clone(),
|
||||||
|
unique_vertices:model.unique_vertices.clone(),
|
||||||
|
texture:group.texture,
|
||||||
|
groups:Vec::new(),
|
||||||
|
instances:model.instances.clone(),
|
||||||
|
});
|
||||||
|
texture_index
|
||||||
|
};
|
||||||
|
unique_texture_models[id+texture_index].groups.push(model::IndexedGroupFixedTexture{
|
||||||
|
polys:group.polys,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut models=Vec::with_capacity(unique_texture_models.len());
|
||||||
|
for model in unique_texture_models.drain(..){
|
||||||
|
let mut vertices = Vec::new();
|
||||||
|
let mut index_from_vertex = std::collections::HashMap::new();//::<IndexedVertex,usize>
|
||||||
|
let mut entities = Vec::new();
|
||||||
|
for group in model.groups {
|
||||||
|
let mut indices = Vec::new();
|
||||||
|
for poly in group.polys {
|
||||||
|
for end_index in 2..poly.vertices.len() {
|
||||||
|
for &index in &[0, end_index - 1, end_index] {
|
||||||
|
let vertex_index = poly.vertices[index];
|
||||||
|
if let Some(&i)=index_from_vertex.get(&vertex_index){
|
||||||
|
indices.push(i);
|
||||||
|
}else{
|
||||||
|
let i=vertices.len() as u16;
|
||||||
|
let vertex=&model.unique_vertices[vertex_index as usize];
|
||||||
|
vertices.push(Vertex {
|
||||||
|
pos: model.unique_pos[vertex.pos as usize],
|
||||||
|
tex: model.unique_tex[vertex.tex as usize],
|
||||||
|
normal: model.unique_normal[vertex.normal as usize],
|
||||||
|
color:model.unique_color[vertex.color as usize],
|
||||||
|
});
|
||||||
|
index_from_vertex.insert(vertex_index,i);
|
||||||
|
indices.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entities.push(indices);
|
||||||
|
}
|
||||||
|
models.push(model::ModelSingleTexture{
|
||||||
|
instances:model.instances,
|
||||||
|
vertices,
|
||||||
|
entities,
|
||||||
|
texture:model.texture,
|
||||||
|
});
|
||||||
|
}
|
||||||
//drain the modeldata vec so entities can be /moved/ to models.entities
|
//drain the modeldata vec so entities can be /moved/ to models.entities
|
||||||
|
let mut model_count=0;
|
||||||
let mut instance_count=0;
|
let mut instance_count=0;
|
||||||
let uniform_buffer_binding_size=<GraphicsData as framework::Example>::required_limits().max_uniform_buffer_binding_size as usize;
|
let uniform_buffer_binding_size=<GraphicsData as framework::Example>::required_limits().max_uniform_buffer_binding_size as usize;
|
||||||
let chunk_size=uniform_buffer_binding_size/MODEL_BUFFER_SIZE_BYTES;
|
let chunk_size=uniform_buffer_binding_size/MODEL_BUFFER_SIZE_BYTES;
|
||||||
self.models.reserve(modeldatas.len());
|
self.models.reserve(models.len());
|
||||||
for modeldata in modeldatas.drain(..) {
|
for model in models.drain(..) {
|
||||||
let n_instances=modeldata.instances.len();
|
instance_count+=model.instances.len();
|
||||||
for instances_chunk in modeldata.instances.rchunks(chunk_size){
|
for instances_chunk in model.instances.rchunks(chunk_size){
|
||||||
instance_count+=1;
|
model_count+=1;
|
||||||
let model_uniforms = get_instances_buffer_data(instances_chunk);
|
let model_uniforms = get_instances_buffer_data(instances_chunk);
|
||||||
let model_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let model_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some(format!("Model{} Buf",instance_count).as_str()),
|
label: Some(format!("Model{} Buf",model_count).as_str()),
|
||||||
contents: bytemuck::cast_slice(&model_uniforms),
|
contents: bytemuck::cast_slice(&model_uniforms),
|
||||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
});
|
});
|
||||||
let texture_view=match modeldata.texture{
|
let texture_view=match model.texture{
|
||||||
Some(texture_id)=>{
|
Some(texture_id)=>{
|
||||||
match double_map.get(&texture_id){
|
match double_map.get(&texture_id){
|
||||||
Some(&mapped_texture_id)=>&texture_views[mapped_texture_id as usize],
|
Some(&mapped_texture_id)=>&texture_views[mapped_texture_id as usize],
|
||||||
@ -175,18 +247,18 @@ impl GraphicsData {
|
|||||||
resource: wgpu::BindingResource::Sampler(&self.samplers.repeat),
|
resource: wgpu::BindingResource::Sampler(&self.samplers.repeat),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: Some(format!("Model{} Bind Group",instance_count).as_str()),
|
label: Some(format!("Model{} Bind Group",model_count).as_str()),
|
||||||
});
|
});
|
||||||
let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Vertex"),
|
label: Some("Vertex"),
|
||||||
contents: bytemuck::cast_slice(&modeldata.vertices),
|
contents: bytemuck::cast_slice(&model.vertices),
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
});
|
});
|
||||||
//all of these are being moved here
|
//all of these are being moved here
|
||||||
self.models.push(ModelGraphics{
|
self.models.push(ModelGraphics{
|
||||||
instances:instances_chunk.to_vec(),
|
instances:instances_chunk.to_vec(),
|
||||||
vertex_buf,
|
vertex_buf,
|
||||||
entities: modeldata.entities.iter().map(|indices|{
|
entities: model.entities.iter().map(|indices|{
|
||||||
let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Index"),
|
label: Some("Index"),
|
||||||
contents: bytemuck::cast_slice(&indices),
|
contents: bytemuck::cast_slice(&indices),
|
||||||
@ -253,43 +325,42 @@ impl framework::Example for GraphicsData {
|
|||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let unit_cube=primitives::the_unit_cube_lol();
|
let mut indexed_models = Vec::new();
|
||||||
let mut modeldatas = Vec::<ModelData>::new();
|
indexed_models.append(&mut model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),*glam::Vec4::ONE.as_ref()));
|
||||||
modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
|
indexed_models.append(&mut model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),*glam::Vec4::ONE.as_ref()));
|
||||||
modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
|
indexed_models.append(&mut model::generate_indexed_model_list_from_obj(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),*glam::Vec4::ONE.as_ref()));
|
||||||
modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
|
indexed_models.push(primitives::the_unit_cube_lol());
|
||||||
modeldatas.append(&mut model::generate_modeldatas(unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE));
|
println!("models.len = {:?}", indexed_models.len());
|
||||||
println!("models.len = {:?}", modeldatas.len());
|
indexed_models[0].instances.push(ModelInstance{
|
||||||
modeldatas[0].instances.push(ModelInstance{
|
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(10.,0.,-10.)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(10.,0.,-10.)),
|
||||||
color:ModelData::COLOR_VEC4_WHITE,
|
color:glam::Vec4::ONE,
|
||||||
});
|
});
|
||||||
//quad monkeys
|
//quad monkeys
|
||||||
modeldatas[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(ModelInstance{
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(10.,5.,10.)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(10.,5.,10.)),
|
||||||
color:ModelData::COLOR_VEC4_WHITE,
|
color:glam::Vec4::ONE,
|
||||||
});
|
});
|
||||||
modeldatas[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(ModelInstance{
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(20.,5.,10.)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(20.,5.,10.)),
|
||||||
color:glam::vec4(1.0,0.0,0.0,1.0),
|
color:glam::vec4(1.0,0.0,0.0,1.0),
|
||||||
});
|
});
|
||||||
modeldatas[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(ModelInstance{
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(10.,5.,20.)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(10.,5.,20.)),
|
||||||
color:glam::vec4(0.0,1.0,0.0,1.0),
|
color:glam::vec4(0.0,1.0,0.0,1.0),
|
||||||
});
|
});
|
||||||
modeldatas[1].instances.push(ModelInstance{
|
indexed_models[1].instances.push(ModelInstance{
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(20.,5.,20.)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(20.,5.,20.)),
|
||||||
color:glam::vec4(0.0,0.0,1.0,1.0),
|
color:glam::vec4(0.0,0.0,1.0,1.0),
|
||||||
});
|
});
|
||||||
//teapot
|
//teapot
|
||||||
modeldatas[2].instances.push(ModelInstance{
|
indexed_models[2].instances.push(ModelInstance{
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(-10.,5.,10.)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(-10.,5.,10.)),
|
||||||
color:ModelData::COLOR_VEC4_WHITE,
|
color:glam::Vec4::ONE,
|
||||||
});
|
});
|
||||||
//ground
|
//ground
|
||||||
modeldatas[3].instances.push(ModelInstance{
|
indexed_models[3].instances.push(ModelInstance{
|
||||||
model_transform:glam::Affine3A::from_translation(glam::vec3(0.,0.,0.))*glam::Affine3A::from_scale(glam::vec3(160.0, 1.0, 160.0)),
|
model_transform:glam::Affine3A::from_translation(glam::vec3(0.,0.,0.))*glam::Affine3A::from_scale(glam::vec3(160.0, 1.0, 160.0)),
|
||||||
color:ModelData::COLOR_VEC4_WHITE,
|
color:glam::Vec4::ONE,
|
||||||
});
|
});
|
||||||
|
|
||||||
let camera_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
let camera_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
@ -525,11 +596,19 @@ impl framework::Example for GraphicsData {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let model_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
bind_group_layouts: &[
|
bind_group_layouts: &[
|
||||||
&camera_bind_group_layout,
|
&camera_bind_group_layout,
|
||||||
|
&skybox_texture_bind_group_layout,
|
||||||
&model_bind_group_layout,
|
&model_bind_group_layout,
|
||||||
|
],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
let sky_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: None,
|
||||||
|
bind_group_layouts: &[
|
||||||
|
&camera_bind_group_layout,
|
||||||
&skybox_texture_bind_group_layout,
|
&skybox_texture_bind_group_layout,
|
||||||
],
|
],
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
@ -538,7 +617,7 @@ impl framework::Example for GraphicsData {
|
|||||||
// Create the render pipelines
|
// Create the render pipelines
|
||||||
let sky_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
let sky_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: Some("Sky Pipeline"),
|
label: Some("Sky Pipeline"),
|
||||||
layout: Some(&pipeline_layout),
|
layout: Some(&sky_pipeline_layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: "vs_sky",
|
entry_point: "vs_sky",
|
||||||
@ -565,7 +644,7 @@ impl framework::Example for GraphicsData {
|
|||||||
});
|
});
|
||||||
let model_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
let model_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: Some("Model Pipeline"),
|
label: Some("Model Pipeline"),
|
||||||
layout: Some(&pipeline_layout),
|
layout: Some(&model_pipeline_layout),
|
||||||
vertex: wgpu::VertexState {
|
vertex: wgpu::VertexState {
|
||||||
module: &shader,
|
module: &shader,
|
||||||
entry_point: "vs_entity_texture",
|
entry_point: "vs_entity_texture",
|
||||||
@ -649,8 +728,12 @@ impl framework::Example for GraphicsData {
|
|||||||
temp_squid_texture_view: squid_texture_view,
|
temp_squid_texture_view: squid_texture_view,
|
||||||
};
|
};
|
||||||
|
|
||||||
graphics.generate_model_physics(&modeldatas);
|
let indexed_model_instances=model::IndexedModelInstances{
|
||||||
graphics.generate_model_graphics(&device,&queue,modeldatas,Vec::new());
|
textures:Vec::new(),
|
||||||
|
models:indexed_models,
|
||||||
|
};
|
||||||
|
graphics.generate_model_physics(&indexed_model_instances);
|
||||||
|
graphics.generate_model_graphics(&device,&queue,indexed_model_instances);
|
||||||
|
|
||||||
return graphics;
|
return graphics;
|
||||||
}
|
}
|
||||||
@ -673,30 +756,30 @@ impl framework::Example for GraphicsData {
|
|||||||
//.snf = "SNBF"
|
//.snf = "SNBF"
|
||||||
if let (Ok(()),Ok(()))=(std::io::Read::read_exact(&mut input, &mut first_8),std::io::Seek::rewind(&mut input)){
|
if let (Ok(()),Ok(()))=(std::io::Read::read_exact(&mut input, &mut first_8),std::io::Seek::rewind(&mut input)){
|
||||||
//
|
//
|
||||||
if let Some(Ok((modeldatas,textures,spawn_point)))={
|
if let Some(Ok((indexed_model_instances,spawn_point)))={
|
||||||
if &first_8==b"<roblox!"{
|
if &first_8==b"<roblox!"{
|
||||||
if let Ok(dom) = rbx_binary::from_reader(input){
|
if let Ok(dom) = rbx_binary::from_reader(input){
|
||||||
Some(load_roblox::generate_modeldatas_roblox(dom))
|
Some(load_roblox::generate_indexed_models_roblox(dom))
|
||||||
}else{
|
}else{
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}else if &first_8==b"<roblox "{
|
}else if &first_8==b"<roblox "{
|
||||||
if let Ok(dom) = rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()){
|
if let Ok(dom) = rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()){
|
||||||
Some(load_roblox::generate_modeldatas_roblox(dom))
|
Some(load_roblox::generate_indexed_models_roblox(dom))
|
||||||
}else{
|
}else{
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
//}else if &first_8[0..4]==b"VBSP"{
|
//}else if &first_8[0..4]==b"VBSP"{
|
||||||
// self.generate_modeldatas_valve(input)
|
// self.generate_indexed_models_valve(input)
|
||||||
}else{
|
}else{
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}{
|
}{
|
||||||
//if generate_modeldatas succeeds, clear the previous ones
|
//if generate_indexed_models succeeds, clear the previous ones
|
||||||
self.models.clear();
|
self.models.clear();
|
||||||
self.physics.models.clear();
|
self.physics.models.clear();
|
||||||
self.generate_model_physics(&modeldatas);
|
self.generate_model_physics(&indexed_model_instances);
|
||||||
self.generate_model_graphics(device,queue,modeldatas,textures);
|
self.generate_model_graphics(device,queue,indexed_model_instances);
|
||||||
//manual reset
|
//manual reset
|
||||||
let time=self.physics.time;
|
let time=self.physics.time;
|
||||||
instruction::InstructionConsumer::process_instruction(&mut self.physics, instruction::TimedInstruction{
|
instruction::InstructionConsumer::process_instruction(&mut self.physics, instruction::TimedInstruction{
|
||||||
@ -859,11 +942,11 @@ impl framework::Example for GraphicsData {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_bind_group(0, &self.bind_groups.camera, &[]);
|
rpass.set_bind_group(0, &self.bind_groups.camera, &[]);
|
||||||
rpass.set_bind_group(2, &self.bind_groups.skybox_texture, &[]);
|
rpass.set_bind_group(1, &self.bind_groups.skybox_texture, &[]);
|
||||||
|
|
||||||
rpass.set_pipeline(&self.pipelines.model);
|
rpass.set_pipeline(&self.pipelines.model);
|
||||||
for model in self.models.iter() {
|
for model in self.models.iter() {
|
||||||
rpass.set_bind_group(1, &model.bind_group, &[]);
|
rpass.set_bind_group(2, &model.bind_group, &[]);
|
||||||
rpass.set_vertex_buffer(0, model.vertex_buf.slice(..));
|
rpass.set_vertex_buffer(0, model.vertex_buf.slice(..));
|
||||||
|
|
||||||
for entity in model.entities.iter() {
|
for entity in model.entities.iter() {
|
||||||
|
133
src/model.rs
133
src/model.rs
@ -3,67 +3,100 @@ use bytemuck::{Pod, Zeroable};
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pub pos: [f32; 3],
|
pub pos: [f32; 3],
|
||||||
pub texture: [f32; 2],
|
pub tex: [f32; 2],
|
||||||
pub normal: [f32; 3],
|
pub normal: [f32; 3],
|
||||||
pub color: [f32; 4],
|
pub color: [f32; 4],
|
||||||
}
|
}
|
||||||
|
#[derive(Clone,Hash,PartialEq,Eq)]
|
||||||
|
pub struct IndexedVertex{
|
||||||
|
pub pos:u32,
|
||||||
|
pub tex:u32,
|
||||||
|
pub normal:u32,
|
||||||
|
pub color:u32,
|
||||||
|
}
|
||||||
|
pub struct IndexedPolygon{
|
||||||
|
pub vertices:Vec<u32>,
|
||||||
|
}
|
||||||
|
pub struct IndexedGroup{
|
||||||
|
pub texture:Option<u32>,//RenderPattern? material/texture/shader/flat color
|
||||||
|
pub polys:Vec<IndexedPolygon>,
|
||||||
|
}
|
||||||
|
pub struct IndexedModel{
|
||||||
|
pub unique_pos:Vec<[f32; 3]>,
|
||||||
|
pub unique_tex:Vec<[f32; 2]>,
|
||||||
|
pub unique_normal:Vec<[f32; 3]>,
|
||||||
|
pub unique_color:Vec<[f32; 4]>,
|
||||||
|
pub unique_vertices:Vec<IndexedVertex>,
|
||||||
|
pub groups: Vec<IndexedGroup>,
|
||||||
|
pub instances:Vec<ModelInstance>,
|
||||||
|
}
|
||||||
|
pub struct IndexedGroupFixedTexture{
|
||||||
|
pub polys:Vec<IndexedPolygon>,
|
||||||
|
}
|
||||||
|
pub struct IndexedModelSingleTexture{
|
||||||
|
pub unique_pos:Vec<[f32; 3]>,
|
||||||
|
pub unique_tex:Vec<[f32; 2]>,
|
||||||
|
pub unique_normal:Vec<[f32; 3]>,
|
||||||
|
pub unique_color:Vec<[f32; 4]>,
|
||||||
|
pub unique_vertices:Vec<IndexedVertex>,
|
||||||
|
pub texture:Option<u32>,//RenderPattern? material/texture/shader/flat color
|
||||||
|
pub groups: Vec<IndexedGroupFixedTexture>,
|
||||||
|
pub instances:Vec<ModelInstance>,
|
||||||
|
}
|
||||||
|
pub struct ModelSingleTexture{
|
||||||
|
pub instances: Vec<ModelInstance>,
|
||||||
|
pub vertices: Vec<Vertex>,
|
||||||
|
pub entities: Vec<Vec<u16>>,
|
||||||
|
pub texture: Option<u32>,
|
||||||
|
}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ModelInstance{
|
pub struct ModelInstance{
|
||||||
pub model_transform:glam::Affine3A,
|
pub model_transform:glam::Affine3A,
|
||||||
pub color:glam::Vec4,
|
pub color:glam::Vec4,
|
||||||
}
|
}
|
||||||
|
pub struct IndexedModelInstances{
|
||||||
#[derive(Clone)]
|
pub textures:Vec<String>,//RenderPattern
|
||||||
pub struct ModelData {
|
pub models:Vec<IndexedModel>,
|
||||||
pub instances: Vec<ModelInstance>,
|
//object_index for spawns, triggers etc?
|
||||||
pub vertices: Vec<Vertex>,
|
|
||||||
pub entities: Vec<Vec<u16>>,
|
|
||||||
pub texture: Option<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModelData {
|
pub fn generate_indexed_model_list_from_obj(data:obj::ObjData,color:[f32;4]) -> Vec<IndexedModel>{
|
||||||
pub const COLOR_FLOATS_WHITE: [f32;4] = [1.0,1.0,1.0,1.0];
|
let mut unique_vertex_index = std::collections::HashMap::<obj::IndexTuple,u32>::new();
|
||||||
pub const COLOR_VEC4_WHITE: glam::Vec4 = glam::vec4(1.0,1.0,1.0,1.0);
|
return data.objects.iter().map(|object|{
|
||||||
}
|
unique_vertex_index.clear();
|
||||||
|
let mut unique_vertices = Vec::new();
|
||||||
pub fn generate_modeldatas(data:obj::ObjData,color:[f32;4]) -> Vec<ModelData>{
|
let groups = object.groups.iter().map(|group|{
|
||||||
let mut modeldatas=Vec::new();
|
IndexedGroup{
|
||||||
let mut vertices = Vec::new();
|
|
||||||
let mut vertex_index = std::collections::HashMap::<obj::IndexTuple,u16>::new();
|
|
||||||
for object in data.objects {
|
|
||||||
vertices.clear();
|
|
||||||
vertex_index.clear();
|
|
||||||
let mut entities = Vec::new();
|
|
||||||
for group in object.groups {
|
|
||||||
let mut indices = Vec::new();
|
|
||||||
for poly in group.polys {
|
|
||||||
for end_index in 2..poly.0.len() {
|
|
||||||
for &index in &[0, end_index - 1, end_index] {
|
|
||||||
let vert = poly.0[index];
|
|
||||||
if let Some(&i)=vertex_index.get(&vert){
|
|
||||||
indices.push(i);
|
|
||||||
}else{
|
|
||||||
let i=vertices.len() as u16;
|
|
||||||
vertices.push(Vertex {
|
|
||||||
pos: data.position[vert.0],
|
|
||||||
texture: data.texture[vert.1.unwrap()],
|
|
||||||
normal: data.normal[vert.2.unwrap()],
|
|
||||||
color,
|
|
||||||
});
|
|
||||||
vertex_index.insert(vert,i);
|
|
||||||
indices.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entities.push(indices);
|
|
||||||
}
|
|
||||||
modeldatas.push(ModelData {
|
|
||||||
instances: Vec::new(),
|
|
||||||
vertices:vertices.clone(),
|
|
||||||
entities,
|
|
||||||
texture:None,
|
texture:None,
|
||||||
|
polys:group.polys.iter().map(|poly|{
|
||||||
|
IndexedPolygon{
|
||||||
|
vertices:poly.0.iter().map(|&tup|{
|
||||||
|
if let Some(&i)=unique_vertex_index.get(&tup){
|
||||||
|
i
|
||||||
|
}else{
|
||||||
|
let i=unique_vertices.len() as u32;
|
||||||
|
unique_vertices.push(IndexedVertex{
|
||||||
|
pos: tup.0 as u32,
|
||||||
|
tex: tup.1.unwrap() as u32,
|
||||||
|
normal: tup.2.unwrap() as u32,
|
||||||
|
color: 0,
|
||||||
});
|
});
|
||||||
|
unique_vertex_index.insert(tup,i);
|
||||||
|
i
|
||||||
}
|
}
|
||||||
modeldatas
|
}).collect()
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
IndexedModel{
|
||||||
|
unique_pos: data.position.clone(),
|
||||||
|
unique_tex: data.texture.clone(),
|
||||||
|
unique_normal: data.normal.clone(),
|
||||||
|
unique_color: vec![color],
|
||||||
|
unique_vertices,
|
||||||
|
groups,
|
||||||
|
instances:Vec::new(),
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
}
|
}
|
@ -1,78 +1,7 @@
|
|||||||
pub fn the_unit_cube_lol() -> obj::ObjData{
|
use crate::model::{IndexedModel, IndexedPolygon, IndexedGroup, IndexedVertex};
|
||||||
generate_partial_unit_cube([Some(glam::Affine2::IDENTITY);6])
|
|
||||||
}
|
const CUBE_DEFAULT_TEXTURE_COORDS:[[f32;2];4]=[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]];
|
||||||
pub fn generate_partial_unit_cube(face_transforms:[Option<glam::Affine2>;6])->obj::ObjData{
|
const CUBE_DEFAULT_VERTICES:[[f32;3];8]=[
|
||||||
let default_polys=[
|
|
||||||
// right (1, 0, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(6,Some(2),Some(0)),
|
|
||||||
obj::IndexTuple(5,Some(1),Some(0)),
|
|
||||||
obj::IndexTuple(2,Some(0),Some(0)),
|
|
||||||
obj::IndexTuple(1,Some(3),Some(0)),
|
|
||||||
]),
|
|
||||||
// top (0, 1, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(5,Some(3),Some(1)),
|
|
||||||
obj::IndexTuple(4,Some(2),Some(1)),
|
|
||||||
obj::IndexTuple(3,Some(1),Some(1)),
|
|
||||||
obj::IndexTuple(2,Some(0),Some(1)),
|
|
||||||
]),
|
|
||||||
// back (0, 0, 1)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(0,Some(3),Some(2)),
|
|
||||||
obj::IndexTuple(1,Some(2),Some(2)),
|
|
||||||
obj::IndexTuple(2,Some(1),Some(2)),
|
|
||||||
obj::IndexTuple(3,Some(0),Some(2)),
|
|
||||||
]),
|
|
||||||
// left (-1, 0, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(0,Some(2),Some(3)),
|
|
||||||
obj::IndexTuple(3,Some(1),Some(3)),
|
|
||||||
obj::IndexTuple(4,Some(0),Some(3)),
|
|
||||||
obj::IndexTuple(7,Some(3),Some(3)),
|
|
||||||
]),
|
|
||||||
// bottom (0,-1, 0)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(1,Some(1),Some(4)),
|
|
||||||
obj::IndexTuple(0,Some(0),Some(4)),
|
|
||||||
obj::IndexTuple(7,Some(3),Some(4)),
|
|
||||||
obj::IndexTuple(6,Some(2),Some(4)),
|
|
||||||
]),
|
|
||||||
// front (0, 0,-1)
|
|
||||||
obj::SimplePolygon(vec![
|
|
||||||
obj::IndexTuple(4,Some(1),Some(5)),
|
|
||||||
obj::IndexTuple(5,Some(0),Some(5)),
|
|
||||||
obj::IndexTuple(6,Some(3),Some(5)),
|
|
||||||
obj::IndexTuple(7,Some(2),Some(5)),
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
let default_verts=[[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]];
|
|
||||||
//generate transformed vertices
|
|
||||||
let mut generated_verts=Vec::new();
|
|
||||||
let mut transforms=Vec::new();
|
|
||||||
let mut generated_polys=Vec::new();
|
|
||||||
for (i,maybe_transform) in face_transforms.iter().enumerate(){
|
|
||||||
if let Some(transform)=maybe_transform{
|
|
||||||
let transform_index=if let Some(transform_index)=transforms.iter().position(|&t|t==transform){
|
|
||||||
transform_index
|
|
||||||
}else{
|
|
||||||
//create new transform_index
|
|
||||||
let transform_index=transforms.len();
|
|
||||||
transforms.push(transform);
|
|
||||||
for vert in default_verts{
|
|
||||||
generated_verts.push(*transform.transform_point2(glam::vec2(vert[0],vert[1])).as_ref());
|
|
||||||
}
|
|
||||||
transform_index
|
|
||||||
};
|
|
||||||
generated_polys.push(obj::SimplePolygon(
|
|
||||||
default_polys[i].0.iter().map(
|
|
||||||
|&v|obj::IndexTuple(v.0,Some(v.1.unwrap()+4*transform_index),v.2)
|
|
||||||
).collect()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obj::ObjData{
|
|
||||||
position: vec![
|
|
||||||
[-1.,-1., 1.],//0 left bottom back
|
[-1.,-1., 1.],//0 left bottom back
|
||||||
[ 1.,-1., 1.],//1 right bottom back
|
[ 1.,-1., 1.],//1 right bottom back
|
||||||
[ 1., 1., 1.],//2 right top back
|
[ 1., 1., 1.],//2 right top back
|
||||||
@ -81,25 +10,161 @@ pub fn generate_partial_unit_cube(face_transforms:[Option<glam::Affine2>;6])->ob
|
|||||||
[ 1., 1.,-1.],//5 right top front
|
[ 1., 1.,-1.],//5 right top front
|
||||||
[ 1.,-1.,-1.],//6 right bottom front
|
[ 1.,-1.,-1.],//6 right bottom front
|
||||||
[-1.,-1.,-1.],//7 left bottom front
|
[-1.,-1.,-1.],//7 left bottom front
|
||||||
],
|
];
|
||||||
texture: generated_verts,
|
const CUBE_DEFAULT_NORMALS:[[f32;3];6]=[
|
||||||
normal: vec![
|
|
||||||
[ 1., 0., 0.],//AabbFace::Right
|
[ 1., 0., 0.],//AabbFace::Right
|
||||||
[ 0., 1., 0.],//AabbFace::Top
|
[ 0., 1., 0.],//AabbFace::Top
|
||||||
[ 0., 0., 1.],//AabbFace::Back
|
[ 0., 0., 1.],//AabbFace::Back
|
||||||
[-1., 0., 0.],//AabbFace::Left
|
[-1., 0., 0.],//AabbFace::Left
|
||||||
[ 0.,-1., 0.],//AabbFace::Bottom
|
[ 0.,-1., 0.],//AabbFace::Bottom
|
||||||
[ 0., 0.,-1.],//AabbFace::Front
|
[ 0., 0.,-1.],//AabbFace::Front
|
||||||
|
];
|
||||||
|
const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[
|
||||||
|
// right (1, 0, 0)
|
||||||
|
[
|
||||||
|
[6,2,0],//[vertex,tex,norm]
|
||||||
|
[5,1,0],
|
||||||
|
[2,0,0],
|
||||||
|
[1,3,0],
|
||||||
],
|
],
|
||||||
objects: vec![obj::Object{
|
// top (0, 1, 0)
|
||||||
name: "Unit Cube".to_owned(),
|
[
|
||||||
groups: vec![obj::Group{
|
[5,3,1],
|
||||||
name: "Cube Vertices".to_owned(),
|
[4,2,1],
|
||||||
index: 0,
|
[3,1,1],
|
||||||
material: None,
|
[2,0,1],
|
||||||
polys: generated_polys,
|
],
|
||||||
}]
|
// 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],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
pub fn the_unit_cube_lol() -> crate::model::IndexedModel{
|
||||||
|
generate_partial_unit_cube([Some(FaceDescription::default());6])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy,Clone)]
|
||||||
|
pub struct FaceDescription{
|
||||||
|
pub texture:Option<u32>,
|
||||||
|
pub transform:glam::Affine2,
|
||||||
|
pub color:glam::Vec4,
|
||||||
|
}
|
||||||
|
impl std::default::Default for FaceDescription{
|
||||||
|
fn default() -> Self {
|
||||||
|
Self{
|
||||||
|
texture:None,
|
||||||
|
transform:glam::Affine2::IDENTITY,
|
||||||
|
color:glam::Vec4::ONE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FaceDescription{
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//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.
|
||||||
|
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();
|
||||||
|
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 (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){
|
||||||
|
transform_index
|
||||||
|
}else{
|
||||||
|
//create new transform_index
|
||||||
|
let transform_index=transforms.len();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
transform_index
|
||||||
|
} 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(),
|
||||||
}],
|
}],
|
||||||
material_libs: Vec::new(),
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -49,13 +49,13 @@ struct ModelInstance{
|
|||||||
//the texture transform then maps the texture coordinates to the location of the specific texture
|
//the texture transform then maps the texture coordinates to the location of the specific texture
|
||||||
//group 1 is the model
|
//group 1 is the model
|
||||||
const MAX_MODEL_INSTANCES=4096;
|
const MAX_MODEL_INSTANCES=4096;
|
||||||
@group(1)
|
@group(2)
|
||||||
@binding(0)
|
@binding(0)
|
||||||
var<uniform> model_instances: array<ModelInstance, MAX_MODEL_INSTANCES>;
|
var<uniform> model_instances: array<ModelInstance, MAX_MODEL_INSTANCES>;
|
||||||
@group(1)
|
@group(2)
|
||||||
@binding(1)
|
@binding(1)
|
||||||
var model_texture: texture_2d<f32>;
|
var model_texture: texture_2d<f32>;
|
||||||
@group(1)
|
@group(2)
|
||||||
@binding(2)
|
@binding(2)
|
||||||
var model_sampler: sampler;
|
var model_sampler: sampler;
|
||||||
|
|
||||||
@ -85,16 +85,16 @@ fn vs_entity_texture(
|
|||||||
}
|
}
|
||||||
|
|
||||||
//group 2 is the skybox texture
|
//group 2 is the skybox texture
|
||||||
@group(2)
|
@group(1)
|
||||||
@binding(0)
|
@binding(0)
|
||||||
var cube_texture: texture_cube<f32>;
|
var cube_texture: texture_cube<f32>;
|
||||||
@group(2)
|
@group(1)
|
||||||
@binding(1)
|
@binding(1)
|
||||||
var cube_sampler: sampler;
|
var cube_sampler: sampler;
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_sky(vertex: SkyOutput) -> @location(0) vec4<f32> {
|
fn fs_sky(vertex: SkyOutput) -> @location(0) vec4<f32> {
|
||||||
return textureSample(cube_texture, model_sampler, vertex.sampledir);
|
return textureSample(cube_texture, cube_sampler, vertex.sampledir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
|
Loading…
Reference in New Issue
Block a user