summaryrefslogtreecommitdiff
path: root/modules/csg
diff options
context:
space:
mode:
Diffstat (limited to 'modules/csg')
-rw-r--r--modules/csg/SCsub3
-rw-r--r--modules/csg/csg.cpp25
-rw-r--r--modules/csg/csg.h10
-rw-r--r--modules/csg/csg_shape.cpp257
-rw-r--r--modules/csg/csg_shape.h17
-rw-r--r--modules/csg/doc_classes/CSGBox3D.xml6
-rw-r--r--modules/csg/doc_classes/CSGCombiner3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGCylinder3D.xml8
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml6
-rw-r--r--modules/csg/doc_classes/CSGPolygon3D.xml9
-rw-r--r--modules/csg/doc_classes/CSGPrimitive3D.xml8
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml6
-rw-r--r--modules/csg/doc_classes/CSGTorus3D.xml8
-rw-r--r--modules/csg/editor/csg_gizmos.cpp (renamed from modules/csg/csg_gizmos.cpp)22
-rw-r--r--modules/csg/editor/csg_gizmos.h (renamed from modules/csg/csg_gizmos.h)8
-rw-r--r--modules/csg/register_types.cpp40
-rw-r--r--modules/csg/register_types.h6
18 files changed, 259 insertions, 188 deletions
diff --git a/modules/csg/SCsub b/modules/csg/SCsub
index 641a42c187..c7307ddefd 100644
--- a/modules/csg/SCsub
+++ b/modules/csg/SCsub
@@ -3,7 +3,10 @@
Import("env")
Import("env_modules")
+# Godot's own source files
env_csg = env_modules.Clone()
# Godot's own source files
env_csg.add_source_files(env.modules_sources, "*.cpp")
+if env["tools"]:
+ env_csg.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 82dc4a4175..93533e1690 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -194,7 +194,7 @@ void CSGBrush::_regen_face_aabbs() {
}
}
-void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces) {
+void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_flip_faces) {
faces.clear();
int vc = p_vertices.size();
@@ -208,10 +208,10 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
const bool *rs = p_smooth.ptr();
int mc = p_materials.size();
const Ref<Material> *rm = p_materials.ptr();
- int ic = p_invert_faces.size();
- const bool *ri = p_invert_faces.ptr();
+ int ic = p_flip_faces.size();
+ const bool *ri = p_flip_faces.ptr();
- Map<Ref<Material>, int> material_map;
+ HashMap<Ref<Material>, int> material_map;
faces.resize(p_vertices.size() / 3);
@@ -242,10 +242,10 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
if (mc == vc / 3) {
Ref<Material> mat = rm[i];
if (mat.is_valid()) {
- const Map<Ref<Material>, int>::Element *E = material_map.find(mat);
+ HashMap<Ref<Material>, int>::ConstIterator E = material_map.find(mat);
if (E) {
- f.material = E->get();
+ f.material = E->value;
} else {
f.material = material_map.size();
material_map[mat] = f.material;
@@ -1336,9 +1336,9 @@ CSGBrushOperation::Build2DFaces::Build2DFaces(const CSGBrush &p_brush, int p_fac
plane = Plane(points_3D[0], points_3D[1], points_3D[2]);
to_3D.origin = points_3D[0];
- to_3D.basis.set_axis(2, plane.normal);
- to_3D.basis.set_axis(0, (points_3D[1] - points_3D[2]).normalized());
- to_3D.basis.set_axis(1, to_3D.basis.get_axis(0).cross(to_3D.basis.get_axis(2)).normalized());
+ to_3D.basis.set_column(2, plane.normal);
+ to_3D.basis.set_column(0, (points_3D[1] - points_3D[2]).normalized());
+ to_3D.basis.set_column(1, to_3D.basis.get_column(0).cross(to_3D.basis.get_column(2)).normalized());
to_2D = to_3D.affine_inverse();
Face2D face;
@@ -1387,13 +1387,13 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
}
// Ensure B has points either side of or in the plane of A.
- int in_plane_count = 0, over_count = 0, under_count = 0;
+ int over_count = 0, under_count = 0;
Plane plane_a(vertices_a[0], vertices_a[1], vertices_a[2]);
ERR_FAIL_COND_MSG(plane_a.normal == Vector3(), "Couldn't form plane from Brush A face.");
for (int i = 0; i < 3; i++) {
if (plane_a.has_point(vertices_b[i])) {
- in_plane_count++;
+ // In plane.
} else if (plane_a.is_point_over(vertices_b[i])) {
over_count++;
} else {
@@ -1406,7 +1406,6 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
}
// Ensure A has points either side of or in the plane of B.
- in_plane_count = 0;
over_count = 0;
under_count = 0;
Plane plane_b(vertices_b[0], vertices_b[1], vertices_b[2]);
@@ -1414,7 +1413,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
for (int i = 0; i < 3; i++) {
if (plane_b.has_point(vertices_a[i])) {
- in_plane_count++;
+ // In plane.
} else if (plane_b.is_point_over(vertices_a[i])) {
over_count++;
} else {
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 9ff7b13a44..53a9e5d722 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -38,8 +38,8 @@
#include "core/math/vector3.h"
#include "core/object/ref_counted.h"
#include "core/templates/list.h"
-#include "core/templates/map.h"
#include "core/templates/oa_hash_map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "scene/resources/material.h"
@@ -139,8 +139,8 @@ struct CSGBrushOperation {
Vector<Vector3> points;
Vector<Face> faces;
- Map<Ref<Material>, int> materials;
- Map<Vector3, int> vertex_map;
+ HashMap<Ref<Material>, int> materials;
+ HashMap<Vector3, int> vertex_map;
OAHashMap<VertexKey, int, VertexKeyHash> snap_cache;
float vertex_snap = 0.0;
@@ -184,8 +184,8 @@ struct CSGBrushOperation {
};
struct Build2DFaceCollection {
- Map<int, Build2DFaces> build2DFacesA;
- Map<int, Build2DFaces> build2DFacesB;
+ HashMap<int, Build2DFaces> build2DFacesA;
+ HashMap<int, Build2DFaces> build2DFacesB;
};
void update_faces(const CSGBrush &p_brush_a, const int p_face_idx_a, const CSGBrush &p_brush_b, const int p_face_idx_b, Build2DFaceCollection &p_collection, float p_vertex_snap);
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 41b4682c84..a5b3db89d9 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -125,7 +125,7 @@ bool CSGShape3D::get_collision_mask_value(int p_layer_number) const {
}
bool CSGShape3D::is_root_shape() const {
- return !parent;
+ return !parent_shape;
}
void CSGShape3D::set_snap(float p_snap) {
@@ -136,13 +136,13 @@ float CSGShape3D::get_snap() const {
return snap;
}
-void CSGShape3D::_make_dirty() {
- if (!is_inside_tree()) {
- return;
+void CSGShape3D::_make_dirty(bool p_parent_removing) {
+ if ((p_parent_removing || is_root_shape()) && !dirty) {
+ call_deferred(SNAME("_update_shape")); // Must be deferred; otherwise, is_root_shape() will use the previous parent
}
- if (parent) {
- parent->_make_dirty();
+ if (!is_root_shape()) {
+ parent_shape->_make_dirty();
} else if (!dirty) {
call_deferred(SNAME("_update_shape"));
}
@@ -164,7 +164,7 @@ CSGBrush *CSGShape3D::_get_brush() {
if (!child) {
continue;
}
- if (!child->is_visible_in_tree()) {
+ if (!child->is_visible()) {
continue;
}
@@ -280,7 +280,7 @@ void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const
}
void CSGShape3D::_update_shape() {
- if (parent || !is_inside_tree()) {
+ if (!is_root_shape()) {
return;
}
@@ -303,17 +303,19 @@ void CSGShape3D::_update_shape() {
ERR_CONTINUE(mat < -1 || mat >= face_count.size());
int idx = mat == -1 ? face_count.size() - 1 : mat;
- Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
+ if (n->faces[i].smooth) {
+ Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]);
- for (int j = 0; j < 3; j++) {
- Vector3 v = n->faces[i].vertices[j];
- Vector3 add;
- if (vec_map.lookup(v, add)) {
- add += p.normal;
- } else {
- add = p.normal;
+ for (int j = 0; j < 3; j++) {
+ Vector3 v = n->faces[i].vertices[j];
+ Vector3 add;
+ if (vec_map.lookup(v, add)) {
+ add += p.normal;
+ } else {
+ add = p.normal;
+ }
+ vec_map.set(v, add);
}
- vec_map.set(v, add);
}
face_count.write[idx]++;
@@ -345,27 +347,6 @@ void CSGShape3D::_update_shape() {
}
}
- // Update collision faces.
- if (root_collision_shape.is_valid()) {
- Vector<Vector3> physics_faces;
- physics_faces.resize(n->faces.size() * 3);
- Vector3 *physicsw = physics_faces.ptrw();
-
- for (int i = 0; i < n->faces.size(); i++) {
- int order[3] = { 0, 1, 2 };
-
- if (n->faces[i].invert) {
- SWAP(order[1], order[2]);
- }
-
- physicsw[i * 3 + 0] = n->faces[i].vertices[order[0]];
- physicsw[i * 3 + 1] = n->faces[i].vertices[order[1]];
- physicsw[i * 3 + 2] = n->faces[i].vertices[order[2]];
- }
-
- root_collision_shape->set_faces(physics_faces);
- }
-
//fill arrays
{
for (int i = 0; i < n->faces.size(); i++) {
@@ -458,6 +439,32 @@ void CSGShape3D::_update_shape() {
}
set_base(root_mesh->get_rid());
+
+ _update_collision_faces();
+}
+
+void CSGShape3D::_update_collision_faces() {
+ if (use_collision && is_root_shape() && root_collision_shape.is_valid()) {
+ CSGBrush *n = _get_brush();
+ ERR_FAIL_COND_MSG(!n, "Cannot get CSGBrush.");
+ Vector<Vector3> physics_faces;
+ physics_faces.resize(n->faces.size() * 3);
+ Vector3 *physicsw = physics_faces.ptrw();
+
+ for (int i = 0; i < n->faces.size(); i++) {
+ int order[3] = { 0, 1, 2 };
+
+ if (n->faces[i].invert) {
+ SWAP(order[1], order[2]);
+ }
+
+ physicsw[i * 3 + 0] = n->faces[i].vertices[order[0]];
+ physicsw[i * 3 + 1] = n->faces[i].vertices[order[1]];
+ physicsw[i * 3 + 2] = n->faces[i].vertices[order[2]];
+ }
+
+ root_collision_shape->set_faces(physics_faces);
+ }
}
AABB CSGShape3D::get_aabb() const {
@@ -486,66 +493,75 @@ Vector<Vector3> CSGShape3D::get_brush_faces() {
return faces;
}
-Vector<Face3> CSGShape3D::get_faces(uint32_t p_usage_flags) const {
- return Vector<Face3>();
-}
-
void CSGShape3D::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
- Node *parentn = get_parent();
- if (parentn) {
- parent = Object::cast_to<CSGShape3D>(parentn);
- if (parent) {
- set_base(RID());
- root_mesh.unref();
+ switch (p_what) {
+ case NOTIFICATION_PARENTED: {
+ Node *parentn = get_parent();
+ if (parentn) {
+ parent_shape = Object::cast_to<CSGShape3D>(parentn);
+ if (parent_shape) {
+ set_base(RID());
+ root_mesh.unref();
+ }
}
- }
-
- if (use_collision && is_root_shape()) {
- root_collision_shape.instantiate();
- root_collision_instance = PhysicsServer3D::get_singleton()->body_create();
- PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC);
- PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
- PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
- PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space());
- PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
- set_collision_layer(collision_layer);
- set_collision_mask(collision_mask);
- }
+ if (!brush || parent_shape) {
+ // Update this node if uninitialized, or both this node and its new parent if it gets added to another CSG shape
+ _make_dirty();
+ }
+ last_visible = is_visible();
+ } break;
- _make_dirty();
- }
+ case NOTIFICATION_UNPARENTED: {
+ if (!is_root_shape()) {
+ // Update this node and its previous parent only if it's currently being removed from another CSG shape
+ _make_dirty(true); // Must be forced since is_root_shape() uses the previous parent
+ }
+ parent_shape = nullptr;
+ } break;
- if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
- if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
- PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
- }
- }
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_root_shape() && last_visible != is_visible()) {
+ // Update this node's parent only if its own visibility has changed, not the visibility of parent nodes
+ parent_shape->_make_dirty();
+ }
+ last_visible = is_visible();
+ } break;
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- if (parent) {
- parent->_make_dirty();
- }
- }
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ if (!is_root_shape()) {
+ // Update this node's parent only if its own transformation has changed, not the transformation of parent nodes
+ parent_shape->_make_dirty();
+ }
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- if (parent) {
- parent->_make_dirty();
- }
- }
+ case NOTIFICATION_ENTER_TREE: {
+ if (use_collision && is_root_shape()) {
+ root_collision_shape.instantiate();
+ root_collision_instance = PhysicsServer3D::get_singleton()->body_create();
+ PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC);
+ PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+ PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid());
+ PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space());
+ PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
+ set_collision_layer(collision_layer);
+ set_collision_mask(collision_mask);
+ _update_collision_faces();
+ }
+ } break;
- if (p_what == NOTIFICATION_EXIT_TREE) {
- if (parent) {
- parent->_make_dirty();
- }
- parent = nullptr;
+ case NOTIFICATION_EXIT_TREE: {
+ if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(root_collision_instance);
+ root_collision_instance = RID();
+ root_collision_shape.unref();
+ }
+ } break;
- if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
- PhysicsServer3D::get_singleton()->free(root_collision_instance);
- root_collision_instance = RID();
- root_collision_shape.unref();
- }
- _make_dirty();
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ if (use_collision && is_root_shape() && root_collision_instance.is_valid()) {
+ PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform());
+ }
+ } break;
}
}
@@ -666,7 +682,7 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver
int ic = invert.size();
bool *w = invert.ptrw();
for (int i = 0; i < ic; i++) {
- w[i] = invert_faces;
+ w[i] = flip_faces;
}
}
brush->build_from_faces(p_vertices, p_uv, p_smooth, p_materials, invert);
@@ -675,28 +691,28 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver
}
void CSGPrimitive3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive3D::set_invert_faces);
- ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive3D::is_inverting_faces);
+ ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &CSGPrimitive3D::set_flip_faces);
+ ClassDB::bind_method(D_METHOD("get_flip_faces"), &CSGPrimitive3D::get_flip_faces);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_faces"), "set_invert_faces", "is_inverting_faces");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
}
-void CSGPrimitive3D::set_invert_faces(bool p_invert) {
- if (invert_faces == p_invert) {
+void CSGPrimitive3D::set_flip_faces(bool p_invert) {
+ if (flip_faces == p_invert) {
return;
}
- invert_faces = p_invert;
+ flip_faces = p_invert;
_make_dirty();
}
-bool CSGPrimitive3D::is_inverting_faces() {
- return invert_faces;
+bool CSGPrimitive3D::get_flip_faces() {
+ return flip_faces;
}
CSGPrimitive3D::CSGPrimitive3D() {
- invert_faces = false;
+ flip_faces = false;
}
/////////////////////
@@ -905,7 +921,7 @@ CSGBrush *CSGSphere3D::_build_brush() {
int face_count = rings * radial_segments * 2 - radial_segments * 2;
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -953,6 +969,10 @@ CSGBrush *CSGSphere3D::_build_brush() {
double u0 = double(j) / radial_segments;
double longitude1 = longitude_step * (j + 1);
+ if (j == radial_segments - 1) {
+ longitude1 = 0;
+ }
+
double x1 = Math::sin(longitude1);
double z1 = Math::cos(longitude1);
double u1 = double(j + 1) / radial_segments;
@@ -1090,7 +1110,7 @@ Ref<Material> CSGSphere3D::get_material() const {
CSGSphere3D::CSGSphere3D() {
// defaults
- radius = 1.0;
+ radius = 0.5;
radial_segments = 12;
rings = 6;
smooth_faces = true;
@@ -1105,7 +1125,7 @@ CSGBrush *CSGBox3D::_build_brush() {
int face_count = 12; //it's a cube..
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1238,7 +1258,7 @@ CSGBrush *CSGCylinder3D::_build_brush() {
int face_count = sides * (cone ? 1 : 2) + sides + (cone ? 0 : sides);
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1269,6 +1289,9 @@ CSGBrush *CSGCylinder3D::_build_brush() {
for (int i = 0; i < sides; i++) {
float inc = float(i) / sides;
float inc_n = float((i + 1)) / sides;
+ if (i == sides - 1) {
+ inc_n = 0;
+ }
float ang = inc * Math_TAU;
float ang_n = inc_n * Math_TAU;
@@ -1451,8 +1474,8 @@ Ref<Material> CSGCylinder3D::get_material() const {
CSGCylinder3D::CSGCylinder3D() {
// defaults
- radius = 1.0;
- height = 1.0;
+ radius = 0.5;
+ height = 2.0;
sides = 8;
cone = false;
smooth_faces = true;
@@ -1480,7 +1503,7 @@ CSGBrush *CSGTorus3D::_build_brush() {
int face_count = ring_sides * sides * 2;
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1509,6 +1532,9 @@ CSGBrush *CSGTorus3D::_build_brush() {
for (int i = 0; i < sides; i++) {
float inci = float(i) / sides;
float inci_n = float((i + 1)) / sides;
+ if (i == sides - 1) {
+ inci_n = 0;
+ }
float angi = inci * Math_TAU;
float angi_n = inci_n * Math_TAU;
@@ -1519,6 +1545,9 @@ CSGBrush *CSGTorus3D::_build_brush() {
for (int j = 0; j < ring_sides; j++) {
float incj = float(j) / ring_sides;
float incj_n = float((j + 1)) / ring_sides;
+ if (j == ring_sides - 1) {
+ incj_n = 0;
+ }
float angj = incj * Math_TAU;
float angj_n = incj_n * Math_TAU;
@@ -1671,8 +1700,8 @@ Ref<Material> CSGTorus3D::get_material() const {
CSGTorus3D::CSGTorus3D() {
// defaults
- inner_radius = 2.0;
- outer_radius = 3.0;
+ inner_radius = 0.5;
+ outer_radius = 1.0;
sides = 8;
ring_sides = 6;
smooth_faces = true;
@@ -1694,7 +1723,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
int shape_sides = shape_polygon.size();
Vector<int> shape_faces = Geometry2D::triangulate_polygon(shape_polygon);
- ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon");
+ ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon. Make sure the polygon doesn't have any intersecting edges.");
// Get polygon enclosing Rect2.
Rect2 shape_rect(shape_polygon[0], Vector2());
@@ -1852,7 +1881,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smoothw[face] = false;
materialsw[face] = material;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
face++;
}
}
@@ -1957,7 +1986,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
uvsw[face * 3 + 2] = u[2];
smoothw[face] = smooth_faces;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
materialsw[face] = material;
face++;
@@ -1972,7 +2001,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
uvsw[face * 3 + 2] = u[0];
smoothw[face] = smooth_faces;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
materialsw[face] = material;
face++;
@@ -1997,7 +2026,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smoothw[face] = false;
materialsw[face] = material;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
face++;
}
}
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index eed995a40e..0eaf5c3727 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -52,13 +52,14 @@ public:
private:
Operation operation = OPERATION_UNION;
- CSGShape3D *parent = nullptr;
+ CSGShape3D *parent_shape = nullptr;
CSGBrush *brush = nullptr;
AABB node_aabb;
bool dirty = false;
+ bool last_visible = false;
float snap = 0.001;
bool use_collision = false;
@@ -104,11 +105,12 @@ private:
const tbool bIsOrientationPreserving, const int iFace, const int iVert);
void _update_shape();
+ void _update_collision_faces();
protected:
void _notification(int p_what);
virtual CSGBrush *_build_brush() = 0;
- void _make_dirty();
+ void _make_dirty(bool p_parent_removing = false);
static void _bind_methods();
@@ -126,7 +128,6 @@ public:
virtual Vector<Vector3> get_brush_faces();
virtual AABB get_aabb() const override;
- virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
void set_use_collision(bool p_enable);
bool is_using_collision() const;
@@ -170,13 +171,13 @@ class CSGPrimitive3D : public CSGShape3D {
GDCLASS(CSGPrimitive3D, CSGShape3D);
protected:
- bool invert_faces;
+ bool flip_faces;
CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials);
static void _bind_methods();
public:
- void set_invert_faces(bool p_invert);
- bool is_inverting_faces();
+ void set_flip_faces(bool p_invert);
+ bool get_flip_faces();
CSGPrimitive3D();
};
@@ -239,7 +240,7 @@ class CSGBox3D : public CSGPrimitive3D {
virtual CSGBrush *_build_brush() override;
Ref<Material> material;
- Vector3 size = Vector3(2, 2, 2);
+ Vector3 size = Vector3(1, 1, 1);
protected:
static void _bind_methods();
@@ -367,7 +368,7 @@ private:
PathRotation path_rotation;
bool path_local;
- Path3D *path;
+ Path3D *path = nullptr;
bool smooth_faces;
bool path_continuous_u;
diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml
index d64e58ae4d..591110fa38 100644
--- a/modules/csg/doc_classes/CSGBox3D.xml
+++ b/modules/csg/doc_classes/CSGBox3D.xml
@@ -1,18 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.0">
+<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Box shape.
</brief_description>
<description>
This node allows you to create a box for use with the CSG system.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the box.
</member>
- <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)">
+ <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(1, 1, 1)">
The box's width, height and depth.
</member>
</members>
diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml
index 422c5d35b7..1601602601 100644
--- a/modules/csg/doc_classes/CSGCombiner3D.xml
+++ b/modules/csg/doc_classes/CSGCombiner3D.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.0">
+<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG node that allows you to combine other CSG modifiers.
</brief_description>
<description>
For complex arrangements of shapes, it is sometimes needed to add structure to your CSG nodes. The CSGCombiner3D node allows you to create this structure. The node encapsulates the result of the CSG operations of its children. In this way, it is possible to do operations on one set of shapes that are children of one CSGCombiner3D node, and a set of separate operations on a second set of shapes that are children of a second CSGCombiner3D node, and then do an operation that takes the two end results as its input to create the final shape.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
</class>
diff --git a/modules/csg/doc_classes/CSGCylinder3D.xml b/modules/csg/doc_classes/CSGCylinder3D.xml
index 40e989bfb3..ea026c5ee9 100644
--- a/modules/csg/doc_classes/CSGCylinder3D.xml
+++ b/modules/csg/doc_classes/CSGCylinder3D.xml
@@ -1,24 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.0">
+<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Cylinder shape.
</brief_description>
<description>
This node allows you to create a cylinder (or cone) for use with the CSG system.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
<member name="cone" type="bool" setter="set_cone" getter="is_cone" default="false">
If [code]true[/code] a cone is created, the [member radius] will only apply to one side.
</member>
- <member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
+ <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
The height of the cylinder.
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the cylinder.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
The radius of the cylinder.
</member>
<member name="sides" type="int" setter="set_sides" getter="get_sides" default="8">
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 2810343139..3318fb21c8 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.0">
+<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Mesh shape that uses a mesh resource.
</brief_description>
<description>
- This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more than two faces.
+ This CSG node allows you to use any mesh resource as a CSG shape, provided it is closed, does not self-intersect, does not contain internal faces and has no edges that connect to more than two faces. See also [CSGPolygon3D] for drawing 2D extruded polygons to be used as CSG nodes.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml
index ecbb7962d1..cacad21453 100644
--- a/modules/csg/doc_classes/CSGPolygon3D.xml
+++ b/modules/csg/doc_classes/CSGPolygon3D.xml
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.0">
+<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Extrudes a 2D polygon shape to create a 3D mesh.
</brief_description>
<description>
- An array of 2D points is extruded to quickly and easily create a variety of 3D meshes.
+ An array of 2D points is extruded to quickly and easily create a variety of 3D meshes. See also [CSGMesh3D] for using 3D meshes as CSG nodes.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
@@ -46,7 +48,8 @@
When [member mode] is [constant MODE_PATH], this is the distance along the path, in meters, the texture coordinates will tile. When set to 0, texture coordinates will match geometry exactly with no tiling.
</member>
<member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)">
- The point array that defines the 2D polygon that is extruded.
+ The point array that defines the 2D polygon that is extruded. This can be a convex or concave polygon with 3 or more points. The polygon must [i]not[/i] have any intersecting edges. Otherwise, triangulation will fail and no mesh will be generated.
+ [b]Note:[/b] If only 1 or 2 points are defined in [member polygon], no mesh will be generated.
</member>
<member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
If [code]true[/code], applies smooth shading to the extrusions.
diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml
index 8f4c8b9451..6ea413c991 100644
--- a/modules/csg/doc_classes/CSGPrimitive3D.xml
+++ b/modules/csg/doc_classes/CSGPrimitive3D.xml
@@ -1,16 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.0">
+<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Base class for CSG primitives.
</brief_description>
<description>
Parent class for various CSG primitives. It contains code and functionality that is common between them. It cannot be used directly. Instead use one of the various classes that inherit from it.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
- <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
- Invert the faces of the mesh.
+ <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false">
+ If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn.
</member>
</members>
</class>
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index f5031064d6..f1cd28e00f 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.0">
+<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
The CSG base class.
</brief_description>
<description>
This is the CSG base class that provides CSG operation support to the various CSG nodes in Godot.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<methods>
<method name="get_collision_layer_value" qualifiers="const">
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
index b8dfb4cf5f..d2f985b3a2 100644
--- a/modules/csg/doc_classes/CSGSphere3D.xml
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.0">
+<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Sphere shape.
</brief_description>
<description>
This node allows you to create a sphere for use with the CSG system.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
@@ -15,7 +17,7 @@
<member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12">
Number of vertical slices for the sphere.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
Radius of the sphere.
</member>
<member name="rings" type="int" setter="set_rings" getter="get_rings" default="6">
diff --git a/modules/csg/doc_classes/CSGTorus3D.xml b/modules/csg/doc_classes/CSGTorus3D.xml
index 91ee63a4c9..ea555a5449 100644
--- a/modules/csg/doc_classes/CSGTorus3D.xml
+++ b/modules/csg/doc_classes/CSGTorus3D.xml
@@ -1,21 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.0">
+<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A CSG Torus shape.
</brief_description>
<description>
This node allows you to create a torus for use with the CSG system.
+ [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay.
</description>
<tutorials>
+ <link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
- <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0">
+ <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="0.5">
The inner radius of the torus.
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the torus.
</member>
- <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="3.0">
+ <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="1.0">
The outer radius of the torus.
</member>
<member name="ring_sides" type="int" setter="set_ring_sides" getter="get_ring_sides" default="6">
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 9a6a33fad3..4d972e46c6 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -29,6 +29,10 @@
/*************************************************************************/
#include "csg_gizmos.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_settings.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
@@ -343,14 +347,12 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
- Array csg_meshes = cs->get_meshes();
- if (csg_meshes.size() != 2) {
- return;
- }
-
- Ref<Mesh> csg_mesh = csg_meshes[1];
- if (csg_mesh.is_valid()) {
- p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ if (cs->is_root_shape()) {
+ Array csg_meshes = cs->get_meshes();
+ Ref<Mesh> csg_mesh = csg_meshes[1];
+ if (csg_mesh.is_valid()) {
+ p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ }
}
if (p_gizmo->is_selected()) {
@@ -419,7 +421,9 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
-EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) {
+EditorPluginCSG::EditorPluginCSG() {
Ref<CSGShape3DGizmoPlugin> gizmo_plugin = Ref<CSGShape3DGizmoPlugin>(memnew(CSGShape3DGizmoPlugin));
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/editor/csg_gizmos.h
index 46761370dd..fa51010f98 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/editor/csg_gizmos.h
@@ -31,7 +31,9 @@
#ifndef CSG_GIZMOS_H
#define CSG_GIZMOS_H
-#include "csg_shape.h"
+#ifdef TOOLS_ENABLED
+
+#include "../csg_shape.h"
#include "editor/editor_plugin.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
@@ -57,7 +59,9 @@ class EditorPluginCSG : public EditorPlugin {
GDCLASS(EditorPluginCSG, EditorPlugin);
public:
- EditorPluginCSG(EditorNode *p_editor);
+ EditorPluginCSG();
};
+#endif // TOOLS_ENABLED
+
#endif // CSG_GIZMOS_H
diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp
index f01907bef3..9b5888dafe 100644
--- a/modules/csg/register_types.cpp
+++ b/modules/csg/register_types.cpp
@@ -30,27 +30,37 @@
#include "register_types.h"
-#include "csg_gizmos.h"
-#include "csg_shape.h"
-
-void register_csg_types() {
#ifndef _3D_DISABLED
- GDREGISTER_VIRTUAL_CLASS(CSGShape3D);
- GDREGISTER_VIRTUAL_CLASS(CSGPrimitive3D);
- GDREGISTER_CLASS(CSGMesh3D);
- GDREGISTER_CLASS(CSGSphere3D);
- GDREGISTER_CLASS(CSGBox3D);
- GDREGISTER_CLASS(CSGCylinder3D);
- GDREGISTER_CLASS(CSGTorus3D);
- GDREGISTER_CLASS(CSGPolygon3D);
- GDREGISTER_CLASS(CSGCombiner3D);
+#include "csg_shape.h"
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<EditorPluginCSG>();
+#include "editor/csg_gizmos.h"
#endif
+
+void initialize_csg_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_ABSTRACT_CLASS(CSGShape3D);
+ GDREGISTER_ABSTRACT_CLASS(CSGPrimitive3D);
+ GDREGISTER_CLASS(CSGMesh3D);
+ GDREGISTER_CLASS(CSGSphere3D);
+ GDREGISTER_CLASS(CSGBox3D);
+ GDREGISTER_CLASS(CSGCylinder3D);
+ GDREGISTER_CLASS(CSGTorus3D);
+ GDREGISTER_CLASS(CSGPolygon3D);
+ GDREGISTER_CLASS(CSGCombiner3D);
+ }
+#ifdef TOOLS_ENABLED
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<EditorPluginCSG>();
+ }
#endif
}
-void unregister_csg_types() {
+void uninitialize_csg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
+
+#endif // _3D_DISABLED
diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h
index 59d84dd52a..ec65adde9c 100644
--- a/modules/csg/register_types.h
+++ b/modules/csg/register_types.h
@@ -31,7 +31,9 @@
#ifndef CSG_REGISTER_TYPES_H
#define CSG_REGISTER_TYPES_H
-void register_csg_types();
-void unregister_csg_types();
+#include "modules/register_module_types.h"
+
+void initialize_csg_module(ModuleInitializationLevel p_level);
+void uninitialize_csg_module(ModuleInitializationLevel p_level);
#endif // CSG_REGISTER_TYPES_H