diff --git a/lib/bsp_loader/src/brush.rs b/lib/bsp_loader/src/brush.rs
index d06c4a8..873b2b4 100644
--- a/lib/bsp_loader/src/brush.rs
+++ b/lib/bsp_loader/src/brush.rs
@@ -1,5 +1,5 @@
-use strafesnet_common::integer::Planar64;
-use strafesnet_common::{model,integer};
+use strafesnet_common::integer::{self,Planar64,Planar64Vec3};
+use strafesnet_common::model::{self,VertexId};
 use strafesnet_common::integer::{vec3::Vector3,Fixed,Ratio};
 
 use crate::{valve_transform_normal,valve_transform_dist};
@@ -212,6 +212,33 @@ impl std::fmt::Display for BrushToMeshError{
 }
 impl core::error::Error for BrushToMeshError{}
 
+fn subdivide_max_area(tris:&mut Vec<Vec<VertexId>>,cw_verts:&[(VertexId,Planar64Vec3)],i0:usize,i2:usize,id0:VertexId,id2:VertexId,v0:Planar64Vec3,v2:Planar64Vec3){
+	if i0+1==i2{
+		return;
+	}
+	let mut best_i1=i0+1;
+	if i0+2<i2{
+		let mut best_area={
+			let (_,v1)=cw_verts[best_i1.rem_euclid(cw_verts.len())];
+			(v2-v0).cross(v1-v0).length_squared()
+		};
+		for i1 in i0+2..=i2-1{
+			let (_,v1)=cw_verts[i1.rem_euclid(cw_verts.len())];
+			let area=(v2-v0).cross(v1-v0).length_squared();
+			if best_area<area{
+				best_i1=i1;
+				best_area=area;
+			}
+		}
+	}
+	let i1=best_i1;
+	let (id1,v1)=cw_verts[i1.rem_euclid(cw_verts.len())];
+	// draw max area first
+	tris.push(vec![id0,id1,id2]);
+	subdivide_max_area(tris,cw_verts,i0,i1,id0,id1,v0,v1);
+	subdivide_max_area(tris,cw_verts,i1,i2,id1,id2,v1,v2);
+}
+
 pub fn faces_to_mesh(faces:Vec<Vec<integer::Planar64Vec3>>)->model::Mesh{
 	// generate the mesh
 	let mut mb=model::MeshBuilder::new();
@@ -220,16 +247,34 @@ pub fn faces_to_mesh(faces:Vec<Vec<integer::Planar64Vec3>>)->model::Mesh{
 	// normals are ignored by physics
 	let normal=mb.acquire_normal_id(integer::vec3::ZERO);
 
-	let polygon_list=faces.into_iter().map(|face|{
-		face.into_iter().map(|pos|{
-			let pos=mb.acquire_pos_id(pos);
-			mb.acquire_vertex_id(model::IndexedVertex{
+	let polygon_list=faces.into_iter().flat_map(|face|{
+		let cw_verts=face.into_iter().map(|position|{
+			let pos=mb.acquire_pos_id(position);
+			(mb.acquire_vertex_id(model::IndexedVertex{
 				pos,
 				tex,
 				normal,
 				color,
-			})
-		}).collect()
+			}),position)
+		}).collect::<Vec<_>>();
+
+		// scan and select maximum area triangle O(n^3)
+		let len=cw_verts.len();
+		let cw_verts=cw_verts.as_slice();
+		let ((i0,i1,i2),(v0,v1,v2))=cw_verts[..len-2].iter().enumerate().flat_map(|(i0,&(_,v0))|
+			cw_verts[i0+1..len-1].iter().enumerate().flat_map(move|(i1,&(_,v1))|
+				cw_verts[i0+i1+2..].iter().enumerate().map(move|(i2,&(_,v2))|((i0,i0+i1+1,i0+i1+i2+2),(v0,v1,v2)))
+			)
+		).max_by_key(|&(_,(v0,v1,v2))|(v2-v0).cross(v1-v0).length_squared()).unwrap();
+		// scan and select more maximum area triangles n * O(n)
+		let mut tris=Vec::with_capacity(len-2);
+		// da big one
+		let (id0,id1,id2)=(cw_verts[i0].0,cw_verts[i1].0,cw_verts[i2].0);
+		tris.push(vec![id0,id1,id2]);
+		subdivide_max_area(&mut tris,cw_verts,i0,i1,id0,id1,v0,v1);
+		subdivide_max_area(&mut tris,cw_verts,i1,i2,id1,id2,v1,v2);
+		subdivide_max_area(&mut tris,cw_verts,i2,i0+len,id2,id0,v2,v0);
+		tris
 	}).collect();
 
 	let polygon_groups=vec![model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list))];