diff --git a/src/bsp.rs b/src/bsp.rs
index 3c0a049..d7dfd31 100644
--- a/src/bsp.rs
+++ b/src/bsp.rs
@@ -13,17 +13,22 @@ where
 	AcquireTextureId:FnMut(&str)->model::TextureId,
 	AcquireMeshId:FnMut(&str)->model::MeshId,
 {
-	let mut name_from_texture_id=Vec::new();
-	let mut texture_id_from_name=std::collections::HashMap::new();
+	let mut unique_render_configs=Vec::new();
 
-	let mut models=bsp.models().map(|world_model|{
+	let mut unique_attributes=Vec::new();
+	unique_attributes.push(gameplay_attributes::CollisionAttributes::contact_default());
+	const TEMP_TOUCH_ME_ATTRIBUTE:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(0);
+
+	let (mut meshes,mut models):(Vec<model::Mesh>,Vec<model::Model>)=bsp.models().enumerate().map(|(i,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 polygon_groups=Vec::new();
+		let mut graphics_groups=Vec::new();
+		let mut physics_group=model::IndexedPhysicsGroup::default();
 		let groups=world_model.faces()
-		.filter(|face|face.is_visible())//TODO: look at this
 		.map(|face|{
 			let face_texture=face.texture();
 			let face_texture_data=face_texture.texture_data();
@@ -32,20 +37,19 @@ where
 			let texture_size=glam::vec2(face_texture_data.width as f32,face_texture_data.height as f32);
 
 			//texture
-			let texture_id=if let Some(&texture_id)=texture_id_from_name.get(face_texture_data.name()){
-				texture_id
-			}else{
-				let texture_id=name_from_texture_id.len() as u32;
-				texture_id_from_name.insert(face_texture_data.name().to_string(),texture_id);
-				name_from_texture_id.push(face_texture_data.name().to_string());
-				texture_id
+			let texture_id=acquire_texture_id(face_texture_data.name());								//this is equivalent to a get_or_create pattern because there is a singular no-texture RenderId
+			//so RenderId==TextureId+1
+			//not the most failsafe code but this is just for the map tool lmao
+			if unique_render_configs.len()==texture_id.get() as usize+1{
+				unique_render_configs.push(model::RenderConfig::texture(texture_id));
 			};
+			let render_id=model::RenderConfigId::new(texture_id.get()+1);
 
 			//normal
 			let normal=face.normal();
 			let normal_idx=spam_normal.len() as u32;
 			spam_normal.push(valve_transform(<[f32;3]>::from(normal)));
-			let mut indices:Vec<u32>=face.vertex_positions().map(|vertex_position|{
+			let mut indices:Vec<model::VertexId>=face.vertex_positions().map(|vertex_position|{
 				let vertex_xyz=<[f32;3]>::from(vertex_position);
 				let pos=glam::Vec3A::from_array(vertex_xyz);
 				let pos_idx=spam_pos.len();
@@ -58,34 +62,46 @@ where
 
 				let i=spam_vertices.len() as u32;
 				spam_vertices.push(model::IndexedVertex{
-					pos: pos_idx as u32,
-					tex: tex_idx as u32,
-					normal: normal_idx,
-					color: 0,
+					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),
 				});
-				i
+				model::VertexId::new(i)
 			}).collect();
 			indices.reverse();
-				texture:Some(texture_id),
-			model::IndexedGroup::PolygonList(vec![model::IndexedPolygon{indices}])
+			let polygon_group_id=model::PolygonGroupId::new(polygon_groups.len() as u32);
+			polygon_groups.push(model::PolygonGroup::PolygonList(model::PolygonList::new(vec![indices])));
+			if face.is_visible(){
+				graphics_groups.push(model::IndexedGraphicsGroup{
+					render:render_id,
+					groups:vec![polygon_group_id],
+				})
+			}
+			physics_group.groups.push(polygon_group_id);
 		}).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,
-			groups,
-			instances:vec![model::Model{
-				attributes:gameplay_attributes::CollisionAttributes::Decoration,
+		(
+			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],
+			},
+			model::Model{
+				mesh:model::MeshId::new(i as u32),
+				attributes:TEMP_TOUCH_ME_ATTRIBUTE,
 				transform:integer::Planar64Affine3::new(
 					integer::Planar64Mat3::default(),
 					valve_transform(<[f32;3]>::from(world_model.origin))
 				),
-				..Default::default()
-			}],
-		}
-	}).collect();
+				color:glam::Vec4::ONE,
+			},
+		)
+	}).unzip();
 
 	//dedupe prop models
 	let mut model_dedupe=std::collections::HashSet::new();
@@ -212,10 +228,11 @@ where
 	//actually add the prop models
 	prop_models.append(&mut models);
 
-	Ok(model::MeshInstances{
-		textures:name_from_texture_id,
-		models:prop_models,
-		spawn_point,
-		modes:Vec::new(),
-	})
+	map::CompleteMap{
+		attributes:unique_attributes,
+		meshes,
+		render_configs:unique_render_configs,
+		models,
+		modes:strafesnet_common::gameplay_modes::Modes::new(Vec::new()),
+	}
 }