From 8eca99fd9c00af217ba93d59d1e0d9ec3abc2abc Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Mon, 3 Feb 2025 17:09:10 -0800
Subject: [PATCH] bsp_loader: rewrite world models to use mesh builder

---
 lib/bsp_loader/src/bsp.rs | 79 +++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 40 deletions(-)

diff --git a/lib/bsp_loader/src/bsp.rs b/lib/bsp_loader/src/bsp.rs
index 12bd173..ca203c5 100644
--- a/lib/bsp_loader/src/bsp.rs
+++ b/lib/bsp_loader/src/bsp.rs
@@ -7,6 +7,31 @@ use strafesnet_deferred_loader::texture::{RenderConfigs,Texture};
 
 use crate::valve_transform;
 
+fn ingest_vertex(
+	mb:&mut model::MeshBuilder,
+	world_position:vbsp::Vector,
+	texture_transform_u:glam::Vec4,
+	texture_transform_v:glam::Vec4,
+	normal:model::NormalId,
+	color:model::ColorId,
+)->model::VertexId{
+	//world_model.origin seems to always be 0,0,0
+	let vertex_xyz=world_position.into();
+	let pos=mb.acquire_pos_id(valve_transform(vertex_xyz));
+
+	//calculate texture coordinates
+	let pos_4d=glam::Vec3::from_array(vertex_xyz).extend(1.0);
+	let tex=glam::vec2(texture_transform_u.dot(pos_4d),texture_transform_v.dot(pos_4d));
+	let tex=mb.acquire_tex_id(tex);
+
+	mb.acquire_vertex_id(model::IndexedVertex{
+		pos,
+		tex,
+		normal,
+		color,
+	})
+}
+
 pub fn convert<'a>(
 	bsp:&'a crate::Bsp,
 	render_config_deferred_loader:&mut RenderConfigDeferredLoader<Cow<'a,str>>,
@@ -48,11 +73,9 @@ pub fn convert<'a>(
 	//the generated MeshIds in here will collide with the Loader Mesh Ids
 	//but I can't think of a good workaround other than just remapping one later.
 	let world_meshes:Vec<model::Mesh>=bsp.models().map(|world_model|{
-		//non-deduplicated
-		let mut spam_pos=Vec::new();
-		let mut spam_tex=Vec::new();
-		let mut spam_normal=Vec::new();
-		let mut spam_vertices=Vec::new();
+		let mut mb=model::MeshBuilder::new();
+
+		let color=mb.acquire_color_id(glam::Vec4::ONE);
 		let mut graphics_groups=Vec::new();
 		let mut physics_group=model::IndexedPhysicsGroup::default();
 		let polygon_groups=world_model.faces().enumerate().map(|(polygon_group_id,face)|{
@@ -68,36 +91,20 @@ pub fn convert<'a>(
 			let render_id=render_config_deferred_loader.acquire_render_config_id(Some(Cow::Borrowed(face_texture_data.name())));
 
 			//normal
-			let normal=face.normal();
-			let normal_idx=spam_normal.len() as u32;
-			spam_normal.push(valve_transform(normal.into()));
-			let mut polygon_iter=face.vertex_positions().map(|vertex_position|{
-				//world_model.origin seems to always be 0,0,0
-				let vertex_xyz=(world_model.origin+vertex_position).into();
-				let pos_idx=spam_pos.len();
-				spam_pos.push(valve_transform(vertex_xyz));
-
-				//calculate texture coordinates
-				let pos=glam::Vec3::from_array(vertex_xyz).extend(1.0);
-				let tex=glam::vec2(texture_transform_u.dot(pos),texture_transform_v.dot(pos));
-				let tex_idx=spam_tex.len() as u32;
-				spam_tex.push(tex);
-
-				let vertex_id=model::VertexId::new(spam_vertices.len() as u32);
-				spam_vertices.push(model::IndexedVertex{
-					pos:model::PositionId::new(pos_idx as u32),
-					tex:model::TextureCoordinateId::new(tex_idx as u32),
-					normal:model::NormalId::new(normal_idx),
-					color:model::ColorId::new(0),
-				});
-				vertex_id
-			});
+			let normal=mb.acquire_normal_id(valve_transform(face.normal().into()));
+			let mut polygon_iter=face.vertex_positions().map(|vertex_position|
+				world_model.origin+vertex_position
+			);
 			let polygon_list=std::iter::from_fn(move||{
 				match (polygon_iter.next(),polygon_iter.next(),polygon_iter.next()){
-					(Some(v1),Some(v2),Some(v3))=>Some(vec![v1,v2,v3]),
+					(Some(v1),Some(v2),Some(v3))=>Some([v1,v2,v3]),
 					//ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate
 					_=>None,
 				}
+			}).map(|triplet|{
+				triplet.map(|world_position|
+					ingest_vertex(&mut mb,world_position,texture_transform_u,texture_transform_v,normal,color)
+				).to_vec()
 			}).collect();
 			if face.is_visible(){
 				//TODO: deduplicate graphics groups by render id
@@ -109,16 +116,8 @@ pub fn convert<'a>(
 			physics_group.groups.push(polygon_group_id);
 			model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list))
 		}).collect();
-		model::Mesh{
-			unique_pos:spam_pos,
-			unique_tex:spam_tex,
-			unique_normal:spam_normal,
-			unique_color:vec![glam::Vec4::ONE],
-			unique_vertices:spam_vertices,
-			polygon_groups,
-			graphics_groups,
-			physics_groups:vec![physics_group],
-		}
+
+		mb.build(polygon_groups,graphics_groups,vec![physics_group])
 	}).collect();
 
 	let world_models:Vec<model::Model>=