Kaynağa Gözat

-Changed how operators work, any shape can operate on any other
-Added some break condition for bad poly data to avoid editor freezes

Juan Linietsky 7 yıl önce
ebeveyn
işleme
f8520dbba7
3 değiştirilmiş dosya ile 105 ekleme ve 131 silme
  1. 17 4
      modules/csg/csg.cpp
  2. 76 112
      modules/csg/csg_shape.cpp
  3. 12 15
      modules/csg/csg_shape.h

+ 17 - 4
modules/csg/csg.cpp

@@ -589,8 +589,6 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in
 		edge_stack.push_back(es);
 	}
 
-	int limit = p_poly.points.size() * 4;
-
 	//attempt to empty the stack.
 	while (edge_stack.size()) {
 
@@ -611,7 +609,9 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in
 
 		edge_process[e.edge] = true; //mark as processed
 
-		while (to_point != e.prev_point) {
+		int limit = p_poly.points.size() * 4; //avoid infinite recursion
+
+		while (to_point != e.prev_point && limit) {
 
 			Vector2 segment[2] = { p_poly.points[prev_point].point, p_poly.points[to_point].point };
 
@@ -621,6 +621,9 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in
 			t2d[1] = Vector2(-t2d[0].y, t2d[0].x); // use as tangent
 			t2d[2] = segment[1]; //origin
 
+			if (t2d.basis_determinant() == 0)
+				break; //abort poly
+
 			t2d.affine_invert();
 
 			//push all edges found here, they will be sorted by minimum angle later.
@@ -677,6 +680,8 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in
 			to_point = next_point;
 			edge_process[next_edge] = true; //mark this edge as processed
 			current_edge = next_edge;
+
+			limit--;
 		}
 
 		//if more than 2 points were added to the polygon, add it to the list of polygons.
@@ -699,7 +704,9 @@ void CSGBrushOperation::_add_poly_outline(const BuildPoly &p_poly, int p_from_po
 	int prev_point = p_from_point;
 	int to_point = p_to_point;
 
-	while (to_point != p_from_point) {
+	int limit = p_poly.points.size() * 4; //avoid infinite recursion
+
+	while (to_point != p_from_point && limit) {
 
 		Vector2 segment[2] = { p_poly.points[prev_point].point, p_poly.points[to_point].point };
 		//again create a transform to compute the angle.
@@ -707,6 +714,10 @@ void CSGBrushOperation::_add_poly_outline(const BuildPoly &p_poly, int p_from_po
 		t2d[0] = (segment[1] - segment[0]).normalized(); //use as Y
 		t2d[1] = Vector2(-t2d[0].y, t2d[0].x); // use as tangent
 		t2d[2] = segment[1]; //origin
+
+		if (t2d.basis_determinant() == 0)
+			break; //abort poly
+
 		t2d.affine_invert();
 
 		float max_angle;
@@ -734,6 +745,8 @@ void CSGBrushOperation::_add_poly_outline(const BuildPoly &p_poly, int p_from_po
 		r_outline.push_back(to_point);
 		prev_point = to_point;
 		to_point = next_point_angle;
+
+		limit--;
 	}
 }
 

+ 76 - 112
modules/csg/csg_shape.cpp

@@ -34,6 +34,14 @@ bool CSGShape::is_root_shape() const {
 	return !parent;
 }
 
+void CSGShape::set_snap(float p_snap) {
+	snap = p_snap;
+}
+
+float CSGShape::get_snap() const {
+	return snap;
+}
+
 void CSGShape::_make_dirty() {
 
 	if (!is_inside_tree())
@@ -60,7 +68,61 @@ CSGBrush *CSGShape::_get_brush() {
 			memdelete(brush);
 		}
 		brush = NULL;
-		brush = _build_brush(&node_aabb);
+
+		CSGBrush *n = _build_brush();
+
+		for (int i = 0; i < get_child_count(); i++) {
+
+			CSGShape *child = Object::cast_to<CSGShape>(get_child(i));
+			if (!child)
+				continue;
+			if (!child->is_visible_in_tree())
+				continue;
+
+			CSGBrush *n2 = child->_get_brush();
+			if (!n2)
+				continue;
+			if (!n) {
+				n = memnew(CSGBrush);
+
+				n->copy_from(*n2, child->get_transform());
+
+			} else {
+
+				CSGBrush *nn = memnew(CSGBrush);
+				CSGBrush *nn2 = memnew(CSGBrush);
+				nn2->copy_from(*n2, child->get_transform());
+
+				CSGBrushOperation bop;
+
+				switch (child->get_operation()) {
+					case CSGShape::OPERATION_UNION: bop.merge_brushes(CSGBrushOperation::OPERATION_UNION, *n, *nn2, *nn, snap); break;
+					case CSGShape::OPERATION_INTERSECTION: bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); break;
+					case CSGShape::OPERATION_SUBTRACTION: bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); break;
+				}
+				memdelete(n);
+				memdelete(nn2);
+				n = nn;
+			}
+		}
+
+		if (n) {
+			AABB aabb;
+			for (int i = 0; i < n->faces.size(); i++) {
+				for (int j = 0; j < 3; j++) {
+					if (i == 0 && j == 0)
+						aabb.position = n->faces[i].vertices[j];
+					else
+						aabb.expand_to(n->faces[i].vertices[j]);
+				}
+			}
+			node_aabb = aabb;
+		} else {
+			node_aabb = AABB();
+		}
+
+		brush = n;
+
 		dirty = false;
 	}
 
@@ -307,23 +369,6 @@ void CSGShape::_validate_property(PropertyInfo &property) const {
 		//hide collision if not root
 		property.usage = PROPERTY_USAGE_NOEDITOR;
 	}
-	if (is_inside_tree() && property.name.begins_with("operation")) {
-		//hide operation for first node or root
-		if (is_root_shape()) {
-			property.usage = PROPERTY_USAGE_NOEDITOR;
-		} else {
-			for (int i = 0; i < get_parent()->get_child_count(); i++) {
-				CSGShape *s = Object::cast_to<CSGShape>(get_parent()->get_child(i));
-				if (!s)
-					continue;
-
-				if (s == this) {
-					property.usage = PROPERTY_USAGE_NOEDITOR;
-				}
-				break;
-			}
-		}
-	}
 }
 
 void CSGShape::_bind_methods() {
@@ -337,8 +382,12 @@ void CSGShape::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape::set_use_collision);
 	ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape::is_using_collision);
 
+	ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap);
+	ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap);
+
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
 
 	BIND_CONSTANT(OPERATION_UNION);
 	BIND_CONSTANT(OPERATION_INTERSECTION);
@@ -352,6 +401,7 @@ CSGShape::CSGShape() {
 	parent = NULL;
 	use_collision = false;
 	operation = OPERATION_UNION;
+	snap = 0.001;
 }
 
 CSGShape::~CSGShape() {
@@ -362,79 +412,12 @@ CSGShape::~CSGShape() {
 }
 //////////////////////////////////
 
-CSGBrush *CSGCombiner::_build_brush(AABB *r_aabb) {
-
-	CSGBrush *n = NULL;
-
-	for (int i = 0; i < get_child_count(); i++) {
-
-		CSGShape *child = Object::cast_to<CSGShape>(get_child(i));
-		if (!child)
-			continue;
-		if (!child->is_visible_in_tree())
-			continue;
-
-		CSGBrush *n2 = child->_get_brush();
-		if (!n2)
-			continue;
-		if (!n) {
-			n = memnew(CSGBrush);
-
-			n->copy_from(*n2, child->get_transform());
-
-		} else {
-
-			CSGBrush *nn = memnew(CSGBrush);
-			CSGBrush *nn2 = memnew(CSGBrush);
-			nn2->copy_from(*n2, child->get_transform());
-
-			CSGBrushOperation bop;
-
-			switch (child->get_operation()) {
-				case CSGShape::OPERATION_UNION: bop.merge_brushes(CSGBrushOperation::OPERATION_UNION, *n, *nn2, *nn, snap); break;
-				case CSGShape::OPERATION_INTERSECTION: bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); break;
-				case CSGShape::OPERATION_SUBTRACTION: bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); break;
-			}
-			memdelete(n);
-			memdelete(nn2);
-			n = nn;
-		}
-	}
-
-	if (n) {
-		AABB aabb;
-		for (int i = 0; i < n->faces.size(); i++) {
-			for (int j = 0; j < 3; j++) {
-				if (i == 0 && j == 0)
-					aabb.position = n->faces[i].vertices[j];
-				else
-					aabb.expand_to(n->faces[i].vertices[j]);
-			}
-		}
-		*r_aabb = aabb;
-	} else {
-		*r_aabb = AABB();
-	}
-	return n;
-}
-
-void CSGCombiner::set_snap(float p_snap) {
-	snap = p_snap;
-}
+CSGBrush *CSGCombiner::_build_brush() {
 
-float CSGCombiner::get_snap() const {
-	return snap;
-}
-
-void CSGCombiner::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGCombiner::set_snap);
-	ClassDB::bind_method(D_METHOD("get_snap"), &CSGCombiner::get_snap);
-
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap");
+	return NULL; //does not build anything
 }
 
 CSGCombiner::CSGCombiner() {
-	snap = 0.001;
 }
 
 /////////////////////
@@ -484,7 +467,7 @@ CSGPrimitive::CSGPrimitive() {
 
 /////////////////////
 
-CSGBrush *CSGMesh::_build_brush(AABB *r_aabb) {
+CSGBrush *CSGMesh::_build_brush() {
 
 	if (!mesh.is_valid())
 		return NULL;
@@ -494,8 +477,6 @@ CSGBrush *CSGMesh::_build_brush(AABB *r_aabb) {
 	PoolVector<Ref<Material> > materials;
 	PoolVector<Vector2> uvs;
 
-	*r_aabb = AABB();
-
 	for (int i = 0; i < mesh->get_surface_count(); i++) {
 
 		if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
@@ -665,7 +646,7 @@ Ref<Mesh> CSGMesh::get_mesh() {
 
 ////////////////////////////////
 
-CSGBrush *CSGSphere::_build_brush(AABB *r_aabb) {
+CSGBrush *CSGSphere::_build_brush() {
 
 	// set our bounding box
 
@@ -781,9 +762,6 @@ CSGBrush *CSGSphere::_build_brush(AABB *r_aabb) {
 
 	brush->build_from_faces(faces, uvs, smooth, materials, invert);
 
-	if (r_aabb) {
-		*r_aabb = AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2, radius * 2, radius * 2));
-	}
 	return brush;
 }
 
@@ -870,7 +848,7 @@ CSGSphere::CSGSphere() {
 
 ///////////////
 
-CSGBrush *CSGBox::_build_brush(AABB *r_aabb) {
+CSGBrush *CSGBox::_build_brush() {
 
 	// set our bounding box
 
@@ -972,9 +950,6 @@ CSGBrush *CSGBox::_build_brush(AABB *r_aabb) {
 
 	brush->build_from_faces(faces, uvs, smooth, materials, invert);
 
-	if (r_aabb) {
-		*r_aabb = AABB(Vector3(-width / 2, -height / 2, -depth / 2), Vector3(width, height, depth));
-	}
 	return brush;
 }
 
@@ -1048,7 +1023,7 @@ CSGBox::CSGBox() {
 
 ///////////////
 
-CSGBrush *CSGCylinder::_build_brush(AABB *r_aabb) {
+CSGBrush *CSGCylinder::_build_brush() {
 
 	// set our bounding box
 
@@ -1181,9 +1156,6 @@ CSGBrush *CSGCylinder::_build_brush(AABB *r_aabb) {
 
 	brush->build_from_faces(faces, uvs, smooth, materials, invert);
 
-	if (r_aabb) {
-		*r_aabb = AABB(Vector3(-radius, -height / 2, -radius), Vector3(radius * 2, height, radius * 2));
-	}
 	return brush;
 }
 
@@ -1286,7 +1258,7 @@ CSGCylinder::CSGCylinder() {
 
 ///////////////
 
-CSGBrush *CSGTorus::_build_brush(AABB *r_aabb) {
+CSGBrush *CSGTorus::_build_brush() {
 
 	// set our bounding box
 
@@ -1409,10 +1381,6 @@ CSGBrush *CSGTorus::_build_brush(AABB *r_aabb) {
 
 	brush->build_from_faces(faces, uvs, smooth, materials, invert);
 
-	if (r_aabb) {
-		*r_aabb = AABB(Vector3(-max_radius, -radius, -max_radius), Vector3(max_radius * 2, radius * 2, max_radius * 2));
-	}
-
 	return brush;
 }
 
@@ -1516,7 +1484,7 @@ CSGTorus::CSGTorus() {
 
 ///////////////
 
-CSGBrush *CSGPolygon::_build_brush(AABB *r_aabb) {
+CSGBrush *CSGPolygon::_build_brush() {
 
 	// set our bounding box
 
@@ -1929,10 +1897,6 @@ CSGBrush *CSGPolygon::_build_brush(AABB *r_aabb) {
 
 	brush->build_from_faces(faces, uvs, smooth, materials, invert);
 
-	if (r_aabb) {
-		*r_aabb = aabb;
-	}
-
 	return brush;
 }
 

+ 12 - 15
modules/csg/csg_shape.h

@@ -27,6 +27,7 @@ private:
 	AABB node_aabb;
 
 	bool dirty;
+	float snap;
 
 	bool use_collision;
 	Ref<ConcavePolygonShape> root_collision_shape;
@@ -59,7 +60,7 @@ private:
 
 protected:
 	void _notification(int p_what);
-	virtual CSGBrush *_build_brush(AABB *r_aabb) = 0;
+	virtual CSGBrush *_build_brush() = 0;
 	void _make_dirty();
 
 	static void _bind_methods();
@@ -81,6 +82,9 @@ public:
 	void set_use_collision(bool p_enable);
 	bool is_using_collision() const;
 
+	void set_snap(float p_snap);
+	float get_snap() const;
+
 	bool is_root_shape() const;
 	CSGShape();
 	~CSGShape();
@@ -91,16 +95,9 @@ VARIANT_ENUM_CAST(CSGShape::Operation)
 class CSGCombiner : public CSGShape {
 	GDCLASS(CSGCombiner, CSGShape)
 private:
-	float snap;
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
-
-protected:
-	static void _bind_methods();
+	virtual CSGBrush *_build_brush();
 
 public:
-	void set_snap(float p_snap);
-	float get_snap() const;
-
 	CSGCombiner();
 };
 
@@ -124,7 +121,7 @@ public:
 class CSGMesh : public CSGPrimitive {
 	GDCLASS(CSGMesh, CSGPrimitive)
 
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
+	virtual CSGBrush *_build_brush();
 
 	Ref<Mesh> mesh;
 
@@ -141,7 +138,7 @@ public:
 class CSGSphere : public CSGPrimitive {
 
 	GDCLASS(CSGSphere, CSGPrimitive)
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
+	virtual CSGBrush *_build_brush();
 
 	Ref<Material> material;
 	bool smooth_faces;
@@ -174,7 +171,7 @@ public:
 class CSGBox : public CSGPrimitive {
 
 	GDCLASS(CSGBox, CSGPrimitive)
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
+	virtual CSGBrush *_build_brush();
 
 	Ref<Material> material;
 	float width;
@@ -203,7 +200,7 @@ public:
 class CSGCylinder : public CSGPrimitive {
 
 	GDCLASS(CSGCylinder, CSGPrimitive)
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
+	virtual CSGBrush *_build_brush();
 
 	Ref<Material> material;
 	float radius;
@@ -240,7 +237,7 @@ public:
 class CSGTorus : public CSGPrimitive {
 
 	GDCLASS(CSGTorus, CSGPrimitive)
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
+	virtual CSGBrush *_build_brush();
 
 	Ref<Material> material;
 	float inner_radius;
@@ -292,7 +289,7 @@ public:
 	};
 
 private:
-	virtual CSGBrush *_build_brush(AABB *r_aabb);
+	virtual CSGBrush *_build_brush();
 
 	Vector<Vector2> polygon;
 	Ref<Material> material;