summaryrefslogtreecommitdiff
path: root/modules/csg
diff options
context:
space:
mode:
Diffstat (limited to 'modules/csg')
-rw-r--r--modules/csg/config.py2
-rw-r--r--modules/csg/csg.cpp90
-rw-r--r--modules/csg/csg.h56
-rw-r--r--modules/csg/csg_gizmos.cpp170
-rw-r--r--modules/csg/csg_gizmos.h26
-rw-r--r--modules/csg/csg_shape.cpp1029
-rw-r--r--modules/csg/csg_shape.h83
-rw-r--r--modules/csg/doc_classes/CSGBox3D.xml14
-rw-r--r--modules/csg/doc_classes/CSGCombiner3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGCylinder3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml7
-rw-r--r--modules/csg/doc_classes/CSGPolygon3D.xml61
-rw-r--r--modules/csg/doc_classes/CSGPrimitive3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml58
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGTorus3D.xml4
-rw-r--r--modules/csg/icons/CSGBox3D.svg7
-rw-r--r--modules/csg/icons/CSGCapsule3D.svg7
-rw-r--r--modules/csg/icons/CSGCombiner3D.svg9
-rw-r--r--modules/csg/icons/CSGCylinder3D.svg7
-rw-r--r--modules/csg/icons/CSGMesh3D.svg7
-rw-r--r--modules/csg/icons/CSGPolygon3D.svg7
-rw-r--r--modules/csg/icons/CSGSphere3D.svg7
-rw-r--r--modules/csg/icons/CSGTorus3D.svg7
-rw-r--r--modules/csg/register_types.cpp22
-rw-r--r--modules/csg/register_types.h4
26 files changed, 743 insertions, 957 deletions
diff --git a/modules/csg/config.py b/modules/csg/config.py
index 9106cbceca..3991b846f9 100644
--- a/modules/csg/config.py
+++ b/modules/csg/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 47982d519a..a7742ef415 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,34 +32,34 @@
#include "core/math/geometry_2d.h"
#include "core/math/math_funcs.h"
-#include "core/sort_array.h"
+#include "core/templates/sort_array.h"
// Static helper functions.
inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2, real_t p_distance) {
- return (p_point1 - p_point2).length_squared() < p_distance * p_distance;
+ return p_point2.distance_squared_to(p_point1) < p_distance * p_distance;
}
-inline static Vector2 interpolate_segment_uv(const Vector2 p_segement_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) {
- float segment_length = (p_segement_points[1] - p_segement_points[0]).length();
- if (segment_length < CMP_EPSILON) {
+inline static Vector2 interpolate_segment_uv(const Vector2 p_segment_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) {
+ if (p_segment_points[0].is_equal_approx(p_segment_points[1])) {
return p_uvs[0];
}
- float distance = (p_interpolation_point - p_segement_points[0]).length();
+ float segment_length = p_segment_points[0].distance_to(p_segment_points[1]);
+ float distance = p_segment_points[0].distance_to(p_interpolation_point);
float fraction = distance / segment_length;
return p_uvs[0].lerp(p_uvs[1], fraction);
}
inline static Vector2 interpolate_triangle_uv(const Vector2 p_vertices[3], const Vector2 p_uvs[3], const Vector2 &p_interpolation_point) {
- if (p_interpolation_point.distance_squared_to(p_vertices[0]) < CMP_EPSILON2) {
+ if (p_interpolation_point.is_equal_approx(p_vertices[0])) {
return p_uvs[0];
}
- if (p_interpolation_point.distance_squared_to(p_vertices[1]) < CMP_EPSILON2) {
+ if (p_interpolation_point.is_equal_approx(p_vertices[1])) {
return p_uvs[1];
}
- if (p_interpolation_point.distance_squared_to(p_vertices[2]) < CMP_EPSILON2) {
+ if (p_interpolation_point.is_equal_approx(p_vertices[2])) {
return p_uvs[2];
}
@@ -156,13 +156,13 @@ inline bool is_point_in_triangle(const Vector3 &p_point, const Vector3 p_vertice
inline static bool is_triangle_degenerate(const Vector2 p_vertices[3], real_t p_vertex_snap2) {
real_t det = p_vertices[0].x * p_vertices[1].y - p_vertices[0].x * p_vertices[2].y +
- p_vertices[0].y * p_vertices[2].x - p_vertices[0].y * p_vertices[1].x +
- p_vertices[1].x * p_vertices[2].y - p_vertices[1].y * p_vertices[2].x;
+ p_vertices[0].y * p_vertices[2].x - p_vertices[0].y * p_vertices[1].x +
+ p_vertices[1].x * p_vertices[2].y - p_vertices[1].y * p_vertices[2].x;
return det < p_vertex_snap2;
}
-inline static bool are_segements_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
+inline static bool are_segments_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
Vector2 segment1 = p_segment1_points[1] - p_segment1_points[0];
Vector2 segment2 = p_segment2_points[1] - p_segment2_points[0];
real_t segment1_length2 = segment1.dot(segment1);
@@ -258,14 +258,14 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
}
materials.resize(material_map.size());
- for (Map<Ref<Material>, int>::Element *E = material_map.front(); E; E = E->next()) {
- materials.write[E->get()] = E->key();
+ for (const KeyValue<Ref<Material>, int> &E : material_map) {
+ materials.write[E.value] = E.key;
}
_regen_face_aabbs();
}
-void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) {
+void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform3D &p_xform) {
faces = p_brush.faces;
materials = p_brush.materials;
@@ -408,7 +408,7 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b
} break;
- case OPERATION_SUBSTRACTION: {
+ case OPERATION_SUBTRACTION: {
int face_count = 0;
for (int i = 0; i < mesh_merge.faces.size(); i++) {
@@ -457,8 +457,8 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b
// Update the list of materials.
r_merged_brush.materials.resize(mesh_merge.materials.size());
- for (const Map<Ref<Material>, int>::Element *E = mesh_merge.materials.front(); E; E = E->next()) {
- r_merged_brush.materials.write[E->get()] = E->key();
+ for (const KeyValue<Ref<Material>, int> &E : mesh_merge.materials) {
+ r_merged_brush.materials.write[E.value] = E.key;
}
}
@@ -517,7 +517,7 @@ int CSGBrushOperation::MeshMerge::_create_bvh(FaceBVH *facebvhptr, FaceBVH **fac
int index = r_max_alloc++;
FaceBVH *_new = &facebvhptr[index];
_new->aabb = aabb;
- _new->center = aabb.position + aabb.size * 0.5;
+ _new->center = aabb.get_center();
_new->face = -1;
_new->left = left;
_new->right = right;
@@ -530,8 +530,8 @@ void CSGBrushOperation::MeshMerge::_add_distance(List<real_t> &r_intersectionsA,
List<real_t> &intersections = p_from_B ? r_intersectionsB : r_intersectionsA;
// Check if distance exists.
- for (const List<real_t>::Element *E = intersections.front(); E; E = E->next()) {
- if (Math::is_equal_approx(**E, p_distance)) {
+ for (const real_t E : intersections) {
+ if (Math::is_equal_approx(E, p_distance)) {
return;
}
}
@@ -589,14 +589,14 @@ bool CSGBrushOperation::MeshMerge::_bvh_inside(FaceBVH *facebvhptr, int p_max_de
Vector3 intersection_point;
// Check if faces are co-planar.
- if ((current_normal - face_normal).length_squared() < CMP_EPSILON2 &&
+ if (current_normal.is_equal_approx(face_normal) &&
is_point_in_triangle(face_center, current_points)) {
// Only add an intersection if not a B face.
if (!face.from_b) {
_add_distance(intersectionsA, intersectionsB, current_face.from_b, 0);
}
} else if (ray_intersects_triangle(face_center, face_normal, current_points, CMP_EPSILON, intersection_point)) {
- real_t distance = (intersection_point - face_center).length();
+ real_t distance = face_center.distance_to(intersection_point);
_add_distance(intersectionsA, intersectionsB, current_face.from_b, distance);
}
}
@@ -678,7 +678,7 @@ void CSGBrushOperation::MeshMerge::mark_inside_faces() {
facebvh[i].aabb.position = points[faces[i].points[0]];
facebvh[i].aabb.expand_to(points[faces[i].points[1]]);
facebvh[i].aabb.expand_to(points[faces[i].points[2]]);
- facebvh[i].center = facebvh[i].aabb.position + facebvh[i].aabb.size * 0.5;
+ facebvh[i].center = facebvh[i].aabb.get_center();
facebvh[i].aabb.grow_by(vertex_snap);
facebvh[i].next = -1;
@@ -781,7 +781,7 @@ void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vect
int CSGBrushOperation::Build2DFaces::_get_point_idx(const Vector2 &p_point) {
for (int vertex_idx = 0; vertex_idx < vertices.size(); ++vertex_idx) {
- if ((p_point - vertices[vertex_idx].point).length_squared() < vertex_snap2) {
+ if (vertices[vertex_idx].point.distance_squared_to(p_point) < vertex_snap2) {
return vertex_idx;
}
}
@@ -911,7 +911,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
vertices[outer_edge_idx[1]].point,
vertices[p_segment_indices[closest_idx]].point
};
- if (are_segements_parallel(edge1, edge2, vertex_snap2)) {
+ if (are_segments_parallel(edge1, edge2, vertex_snap2)) {
if (!degenerate_points.find(outer_edge_idx[0])) {
degenerate_points.push_back(outer_edge_idx[0]);
}
@@ -931,7 +931,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
// Delete the old faces in reverse index order.
merge_faces_idx.sort();
- merge_faces_idx.invert();
+ merge_faces_idx.reverse();
for (int i = 0; i < merge_faces_idx.size(); ++i) {
faces.remove(merge_faces_idx[i]);
}
@@ -961,7 +961,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
// Check if point is existing face vertex.
bool existing = false;
for (int i = 0; i < 3; ++i) {
- if ((point_2D - face_vertices[i].point).length_squared() < vertex_snap2) {
+ if (face_vertices[i].point.distance_squared_to(point_2D) < vertex_snap2) {
existing = true;
break;
}
@@ -970,7 +970,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
continue;
}
- // Check if point is on an each edge.
+ // Check if point is on each edge.
for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) {
Vector2 edge_points[2] = {
face_points[face_edge_idx],
@@ -978,7 +978,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
};
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point_2D, edge_points);
- if ((closest_point - point_2D).length_squared() < vertex_snap2) {
+ if (point_2D.distance_squared_to(closest_point) < vertex_snap2) {
int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3];
// If new vertex snaps to degenerate vertex, just delete this face.
@@ -1041,7 +1041,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
bool on_edge = false;
for (int edge_point_idx = 0; edge_point_idx < 2; ++edge_point_idx) {
intersection_point = Geometry2D::get_closest_point_to_segment(p_segment_points[edge_point_idx], edge_points);
- if ((intersection_point - p_segment_points[edge_point_idx]).length_squared() < vertex_snap2) {
+ if (p_segment_points[edge_point_idx].distance_squared_to(intersection_point) < vertex_snap2) {
on_edge = true;
break;
}
@@ -1050,13 +1050,13 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
// Else check if the segment intersects the edge.
if (on_edge || Geometry2D::segment_intersects_segment(p_segment_points[0], p_segment_points[1], edge_points[0], edge_points[1], &intersection_point)) {
// Check if intersection point is an edge point.
- if ((intersection_point - edge_points[0]).length_squared() < vertex_snap2 ||
- (intersection_point - edge_points[1]).length_squared() < vertex_snap2) {
+ if ((edge_points[0].distance_squared_to(intersection_point) < vertex_snap2) ||
+ (edge_points[1].distance_squared_to(intersection_point) < vertex_snap2)) {
continue;
}
// Check if edge exists, by checking if the intersecting segment is parallel to the edge.
- if (are_segements_parallel(p_segment_points, edge_points, vertex_snap2)) {
+ if (are_segments_parallel(p_segment_points, edge_points, vertex_snap2)) {
continue;
}
@@ -1076,9 +1076,9 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
break;
}
- // If opposite point is on the segemnt, add its index to segment indices too.
+ // If opposite point is on the segment, add its index to segment indices too.
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(vertices[opposite_vertex_idx].point, p_segment_points);
- if ((closest_point - vertices[opposite_vertex_idx].point).length_squared() < vertex_snap2) {
+ if (vertices[opposite_vertex_idx].point.distance_squared_to(closest_point) < vertex_snap2) {
_add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx);
}
@@ -1132,12 +1132,12 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
// Check if point is existing face vertex.
for (int i = 0; i < 3; ++i) {
- if ((p_point - face_vertices[i].point).length_squared() < vertex_snap2) {
+ if (face_vertices[i].point.distance_squared_to(p_point) < vertex_snap2) {
return face.vertex_idx[i];
}
}
- // Check if point is on an each edge.
+ // Check if point is on each edge.
bool on_edge = false;
for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) {
Vector2 edge_points[2] = {
@@ -1150,7 +1150,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
};
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, edge_points);
- if ((closest_point - p_point).length_squared() < vertex_snap2) {
+ if (p_point.distance_squared_to(closest_point) < vertex_snap2) {
on_edge = true;
// Add the point as a new vertex.
@@ -1172,8 +1172,8 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] };
Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] };
Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point };
- if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) &&
- are_segements_parallel(split_edge2, new_edge, vertex_snap2)) {
+ if (are_segments_parallel(split_edge1, new_edge, vertex_snap2) &&
+ are_segments_parallel(split_edge2, new_edge, vertex_snap2)) {
break;
}
@@ -1400,7 +1400,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
under_count++;
}
}
- // If all points under or over the plane, there is no intesection.
+ // If all points under or over the plane, there is no intersection.
if (over_count == 3 || under_count == 3) {
return;
}
@@ -1421,7 +1421,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
under_count++;
}
}
- // If all points under or over the plane, there is no intesection.
+ // If all points under or over the plane, there is no intersection.
if (over_count == 3 || under_count == 3) {
return;
}
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 34ee239c17..b1fe933268 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,16 +31,16 @@
#ifndef CSG_H
#define CSG_H
-#include "core/list.h"
-#include "core/map.h"
#include "core/math/aabb.h"
#include "core/math/plane.h"
-#include "core/math/transform.h"
+#include "core/math/transform_3d.h"
#include "core/math/vector2.h"
#include "core/math/vector3.h"
-#include "core/oa_hash_map.h"
-#include "core/reference.h"
-#include "core/vector.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/vector.h"
#include "scene/resources/material.h"
struct CSGBrush {
@@ -48,9 +48,9 @@ struct CSGBrush {
Vector3 vertices[3];
Vector2 uvs[3];
AABB aabb;
- bool smooth;
- bool invert;
- int material;
+ bool smooth = false;
+ bool invert = false;
+ int material = 0;
};
Vector<Face> faces;
@@ -60,34 +60,34 @@ struct CSGBrush {
// Create a brush from faces.
void 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 copy_from(const CSGBrush &p_brush, const Transform &p_xform);
+ void copy_from(const CSGBrush &p_brush, const Transform3D &p_xform);
};
struct CSGBrushOperation {
enum Operation {
OPERATION_UNION,
OPERATION_INTERSECTION,
- OPERATION_SUBSTRACTION,
+ OPERATION_SUBTRACTION,
};
void merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap);
struct MeshMerge {
struct Face {
- bool from_b;
- bool inside;
- int points[3];
+ bool from_b = false;
+ bool inside = false;
+ int points[3] = {};
Vector2 uvs[3];
- bool smooth;
- bool invert;
- int material_idx;
+ bool smooth = false;
+ bool invert = false;
+ int material_idx = 0;
};
struct FaceBVH {
- int face;
- int left;
- int right;
- int next;
+ int face = 0;
+ int left = 0;
+ int right = 0;
+ int next = 0;
Vector3 center;
AABB aabb;
};
@@ -142,7 +142,7 @@ struct CSGBrushOperation {
Map<Ref<Material>, int> materials;
Map<Vector3, int> vertex_map;
OAHashMap<VertexKey, int, VertexKeyHash> snap_cache;
- float vertex_snap;
+ float vertex_snap = 0.0;
inline void _add_distance(List<real_t> &r_intersectionsA, List<real_t> &r_intersectionsB, bool p_from_B, real_t p_distance) const;
inline bool _bvh_inside(FaceBVH *facebvhptr, int p_max_depth, int p_bvh_first, int p_face_idx) const;
@@ -159,15 +159,15 @@ struct CSGBrushOperation {
};
struct Face2D {
- int vertex_idx[3];
+ int vertex_idx[3] = {};
};
Vector<Vertex2D> vertices;
Vector<Face2D> faces;
Plane plane;
- Transform to_2D;
- Transform to_3D;
- float vertex_snap2;
+ Transform3D to_2D;
+ Transform3D to_3D;
+ float vertex_snap2 = 0.0;
inline int _get_point_idx(const Vector2 &p_point);
inline int _add_vertex(const Vertex2D &p_vertex);
diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp
index cce72770f5..2f8b354bb7 100644
--- a/modules/csg/csg_gizmos.cpp
+++ b/modules/csg/csg_gizmos.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,8 @@
/*************************************************************************/
#include "csg_gizmos.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
///////////
@@ -48,7 +50,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
create_handle_material("handles");
}
-String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const {
+String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere3D>(cs)) {
@@ -56,22 +58,21 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo,
}
if (Object::cast_to<CSGBox3D>(cs)) {
- static const char *hname[3] = { "Width", "Height", "Depth" };
- return hname[p_idx];
+ return "Size";
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
- return p_idx == 0 ? "Radius" : "Height";
+ return p_id == 0 ? "Radius" : "Height";
}
if (Object::cast_to<CSGTorus3D>(cs)) {
- return p_idx == 0 ? "InnerRadius" : "OuterRadius";
+ return p_id == 0 ? "InnerRadius" : "OuterRadius";
}
return "";
}
-Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const {
+Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere3D>(cs)) {
@@ -81,35 +82,28 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int
if (Object::cast_to<CSGBox3D>(cs)) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
- switch (p_idx) {
- case 0:
- return s->get_width();
- case 1:
- return s->get_height();
- case 2:
- return s->get_depth();
- }
+ return s->get_size();
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
- return p_idx == 0 ? s->get_radius() : s->get_height();
+ return p_id == 0 ? s->get_radius() : s->get_height();
}
if (Object::cast_to<CSGTorus3D>(cs)) {
CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs);
- return p_idx == 0 ? s->get_inner_radius() : s->get_outer_radius();
+ return p_id == 0 ? s->get_inner_radius() : s->get_outer_radius();
}
return Variant();
}
-void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) {
+void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
- Transform gt = cs->get_global_transform();
+ Transform3D gt = cs->get_global_transform();
//gt.orthonormalize();
- Transform gi = gt.affine_inverse();
+ Transform3D gi = gt.affine_inverse();
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
@@ -123,7 +117,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Geometry3D::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
float d = ra.x;
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
@@ -137,50 +131,48 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
Vector3 axis;
- axis[p_idx] = 1.0;
+ axis[p_id] = 1.0;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_idx];
+ float d = ra[p_id];
+
+ if (Math::is_nan(d)) {
+ // The handle is perpendicular to the camera.
+ return;
+ }
+
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
- switch (p_idx) {
- case 0:
- s->set_width(d * 2);
- break;
- case 1:
- s->set_height(d * 2);
- break;
- case 2:
- s->set_depth(d * 2);
- break;
- }
+ Vector3 h = s->get_size();
+ h[p_id] = d * 2;
+ s->set_size(h);
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
Vector3 axis;
- axis[p_idx == 0 ? 0 : 1] = 1.0;
+ axis[p_id == 0 ? 0 : 1] = 1.0;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
- if (p_idx == 0) {
+ if (p_id == 0) {
s->set_radius(d);
- } else if (p_idx == 1) {
+ } else if (p_id == 1) {
s->set_height(d * 2.0);
}
}
@@ -194,22 +186,22 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap());
+ d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
}
if (d < 0.001) {
d = 0.001;
}
- if (p_idx == 0) {
+ if (p_id == 0) {
s->set_inner_radius(d);
- } else if (p_idx == 1) {
+ } else if (p_id == 1) {
s->set_outer_radius(d);
}
}
}
-void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
+void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
if (Object::cast_to<CSGSphere3D>(cs)) {
@@ -229,45 +221,21 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx,
if (Object::cast_to<CSGBox3D>(cs)) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
if (p_cancel) {
- switch (p_idx) {
- case 0:
- s->set_width(p_restore);
- break;
- case 1:
- s->set_height(p_restore);
- break;
- case 2:
- s->set_depth(p_restore);
- break;
- }
+ s->set_size(p_restore);
return;
}
UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change Box Shape Extents"));
- static const char *method[3] = { "set_width", "set_height", "set_depth" };
- float current = 0;
- switch (p_idx) {
- case 0:
- current = s->get_width();
- break;
- case 1:
- current = s->get_height();
- break;
- case 2:
- current = s->get_depth();
- break;
- }
-
- ur->add_do_method(s, method[p_idx], current);
- ur->add_undo_method(s, method[p_idx], p_restore);
+ ur->create_action(TTR("Change Box Shape Size"));
+ ur->add_do_method(s, "set_size", s->get_size());
+ ur->add_undo_method(s, "set_size", p_restore);
ur->commit_action();
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs);
if (p_cancel) {
- if (p_idx == 0) {
+ if (p_id == 0) {
s->set_radius(p_restore);
} else {
s->set_height(p_restore);
@@ -276,7 +244,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx,
}
UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
- if (p_idx == 0) {
+ if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
ur->add_undo_method(s, "set_radius", p_restore);
@@ -292,7 +260,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx,
if (Object::cast_to<CSGTorus3D>(cs)) {
CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs);
if (p_cancel) {
- if (p_idx == 0) {
+ if (p_id == 0) {
s->set_inner_radius(p_restore);
} else {
s->set_outer_radius(p_restore);
@@ -301,7 +269,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx,
}
UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
- if (p_idx == 0) {
+ if (p_id == 0) {
ur->create_action(TTR("Change Torus Inner Radius"));
ur->add_do_method(s, "set_inner_radius", s->get_inner_radius());
ur->add_undo_method(s, "set_inner_radius", p_restore);
@@ -319,7 +287,7 @@ bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial);
}
-String CSGShape3DGizmoPlugin::get_name() const {
+String CSGShape3DGizmoPlugin::get_gizmo_name() const {
return "CSGShape3D";
}
@@ -332,27 +300,16 @@ bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const {
}
void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
-
p_gizmo->clear();
- Ref<Material> material;
- switch (cs->get_operation()) {
- case CSGShape3D::OPERATION_UNION:
- material = get_material("shape_union_material", p_gizmo);
- break;
- case CSGShape3D::OPERATION_INTERSECTION:
- material = get_material("shape_intersection_material", p_gizmo);
- break;
- case CSGShape3D::OPERATION_SUBTRACTION:
- material = get_material("shape_subtraction_material", p_gizmo);
- break;
- }
-
- Ref<Material> handles_material = get_material("handles");
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
Vector<Vector3> faces = cs->get_brush_faces();
+ if (faces.size() == 0) {
+ return;
+ }
+
Vector<Vector3> lines;
lines.resize(faces.size() * 2);
{
@@ -368,6 +325,21 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
+ Ref<Material> material;
+ switch (cs->get_operation()) {
+ case CSGShape3D::OPERATION_UNION:
+ material = get_material("shape_union_material", p_gizmo);
+ break;
+ case CSGShape3D::OPERATION_INTERSECTION:
+ material = get_material("shape_intersection_material", p_gizmo);
+ break;
+ case CSGShape3D::OPERATION_SUBTRACTION:
+ material = get_material("shape_subtraction_material", p_gizmo);
+ break;
+ }
+
+ Ref<Material> handles_material = get_material("handles");
+
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
@@ -392,7 +364,7 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
break;
}
- p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), solid_material);
+ p_gizmo->add_mesh(mesh, solid_material);
}
if (Object::cast_to<CSGSphere3D>(cs)) {
@@ -408,9 +380,13 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
Vector<Vector3> handles;
- handles.push_back(Vector3(s->get_width() * 0.5, 0, 0));
- handles.push_back(Vector3(0, s->get_height() * 0.5, 0));
- handles.push_back(Vector3(0, 0, s->get_depth() * 0.5));
+
+ for (int i = 0; i < 3; i++) {
+ Vector3 h;
+ h[i] = s->get_size()[i] / 2;
+ handles.push_back(h);
+ }
+
p_gizmo->add_handles(handles, handles_material);
}
diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h
index 83ee847caf..2a6ab91102 100644
--- a/modules/csg/csg_gizmos.h
+++ b/modules/csg/csg_gizmos.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,22 +33,22 @@
#include "csg_shape.h"
#include "editor/editor_plugin.h"
-#include "editor/node_3d_editor_gizmos.h"
+#include "editor/plugins/node_3d_editor_gizmos.h"
class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CSGShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
- bool has_gizmo(Node3D *p_spatial) override;
- String get_name() const override;
- int get_priority() const override;
- bool is_selectable_when_hidden() const override;
- void redraw(EditorNode3DGizmo *p_gizmo) override;
-
- String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const override;
- Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const override;
- void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override;
- void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) override;
+ virtual bool has_gizmo(Node3D *p_spatial) override;
+ virtual String get_gizmo_name() const override;
+ virtual int get_priority() const override;
+ virtual bool is_selectable_when_hidden() const override;
+ virtual void redraw(EditorNode3DGizmo *p_gizmo) override;
+
+ virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override;
+ virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) override;
CSGShape3DGizmoPlugin();
};
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 8f2ebc7232..b9be7535dc 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,8 +29,8 @@
/*************************************************************************/
#include "csg_shape.h"
+
#include "core/math/geometry_2d.h"
-#include "scene/3d/path_3d.h"
void CSGShape3D::set_use_collision(bool p_enable) {
if (use_collision == p_enable) {
@@ -44,8 +44,9 @@ void CSGShape3D::set_use_collision(bool p_enable) {
}
if (use_collision) {
- root_collision_shape.instance();
- root_collision_instance = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ 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());
@@ -58,7 +59,7 @@ void CSGShape3D::set_use_collision(bool p_enable) {
root_collision_instance = RID();
root_collision_shape.unref();
}
- _change_notify();
+ notify_property_list_changed();
}
bool CSGShape3D::is_using_collision() const {
@@ -87,32 +88,40 @@ uint32_t CSGShape3D::get_collision_mask() const {
return collision_mask;
}
-void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
+void CSGShape3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t collision_layer = get_collision_layer();
if (p_value) {
- mask |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_mask(mask);
+ set_collision_layer(collision_layer);
}
-bool CSGShape3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
+bool CSGShape3D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
+void CSGShape3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(mask);
+ set_collision_mask(mask);
}
-bool CSGShape3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
+bool CSGShape3D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool CSGShape3D::is_root_shape() const {
@@ -135,7 +144,7 @@ void CSGShape3D::_make_dirty() {
if (parent) {
parent->_make_dirty();
} else if (!dirty) {
- call_deferred("_update_shape");
+ call_deferred(SNAME("_update_shape"));
}
dirty = true;
@@ -183,7 +192,7 @@ CSGBrush *CSGShape3D::_get_brush() {
bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap);
break;
case CSGShape3D::OPERATION_SUBTRACTION:
- bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap);
+ bop.merge_brushes(CSGBrushOperation::OPERATION_SUBTRACTION, *n, *nn2, *nn, snap);
break;
}
memdelete(n);
@@ -271,7 +280,7 @@ void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const
}
void CSGShape3D::_update_shape() {
- if (parent) {
+ if (parent || !is_inside_tree()) {
return;
}
@@ -406,7 +415,7 @@ void CSGShape3D::_update_shape() {
}
}
- root_mesh.instance();
+ root_mesh.instantiate();
//create surfaces
for (int i = 0; i < surfaces.size(); i++) {
@@ -493,8 +502,9 @@ void CSGShape3D::_notification(int p_what) {
}
if (use_collision && is_root_shape()) {
- root_collision_shape.instance();
- root_collision_instance = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC);
+ 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());
@@ -542,7 +552,7 @@ void CSGShape3D::_notification(int p_what) {
void CSGShape3D::set_operation(Operation p_operation) {
operation = p_operation;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
CSGShape3D::Operation CSGShape3D::get_operation() const {
@@ -562,17 +572,18 @@ void CSGShape3D::_validate_property(PropertyInfo &property) const {
bool is_collision_prefixed = property.name.begins_with("collision_");
if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
//hide collision if not root
- property.usage = PROPERTY_USAGE_NOEDITOR;
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
} else if (is_collision_prefixed && !bool(get("use_collision"))) {
- property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
}
+ GeometryInstance3D::_validate_property(property);
}
Array CSGShape3D::get_meshes() const {
if (root_mesh.is_valid()) {
Array arr;
arr.resize(2);
- arr[0] = Transform();
+ arr[0] = Transform3D();
arr[1] = root_mesh;
return arr;
}
@@ -599,11 +610,11 @@ void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CSGShape3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape3D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CSGShape3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CSGShape3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CSGShape3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CSGShape3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CSGShape3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents);
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents);
@@ -625,15 +636,6 @@ void CSGShape3D::_bind_methods() {
}
CSGShape3D::CSGShape3D() {
- operation = OPERATION_UNION;
- parent = nullptr;
- brush = nullptr;
- dirty = false;
- snap = 0.001;
- use_collision = false;
- collision_layer = 1;
- collision_mask = 1;
- calculate_tangents = true;
set_notify_local_transform(true);
}
@@ -701,7 +703,7 @@ CSGPrimitive3D::CSGPrimitive3D() {
CSGBrush *CSGMesh3D::_build_brush() {
if (!mesh.is_valid()) {
- return nullptr;
+ return memnew(CSGBrush);
}
Vector<Vector3> vertices;
@@ -719,7 +721,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
if (arrays.size() == 0) {
_make_dirty();
- ERR_FAIL_COND_V(arrays.size() == 0, nullptr);
+ ERR_FAIL_COND_V(arrays.size() == 0, memnew(CSGBrush));
}
Vector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX];
@@ -781,7 +783,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
}
}
- bool flat = normal[0].distance_to(normal[1]) < CMP_EPSILON && normal[0].distance_to(normal[2]) < CMP_EPSILON;
+ bool flat = normal[0].is_equal_approx(normal[1]) && normal[0].is_equal_approx(normal[2]);
vw[as + j + 0] = vertex[0];
vw[as + j + 1] = vertex[1];
@@ -823,7 +825,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
}
}
- bool flat = normal[0].distance_to(normal[1]) < CMP_EPSILON && normal[0].distance_to(normal[2]) < CMP_EPSILON;
+ bool flat = normal[0].is_equal_approx(normal[1]) && normal[0].is_equal_approx(normal[2]);
vw[as + j + 0] = vertex[0];
vw[as + j + 1] = vertex[1];
@@ -840,7 +842,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
}
if (vertices.size() == 0) {
- return nullptr;
+ return memnew(CSGBrush);
}
return _create_brush_from_arrays(vertices, uvs, smooth, materials);
@@ -848,7 +850,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
void CSGMesh3D::_mesh_changed() {
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
void CSGMesh3D::set_material(const Ref<Material> &p_material) {
@@ -871,7 +873,7 @@ void CSGMesh3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_material"), &CSGMesh3D::get_material);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) {
@@ -887,7 +889,7 @@ void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) {
mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed));
}
- _make_dirty();
+ _mesh_changed();
}
Ref<Mesh> CSGMesh3D::get_mesh() {
@@ -926,47 +928,51 @@ CSGBrush *CSGSphere3D::_build_brush() {
Ref<Material> *materialsw = materials.ptrw();
bool *invertw = invert.ptrw();
+ // We want to follow an order that's convenient for UVs.
+ // For latitude step we start at the top and move down like in an image.
+ const double latitude_step = -Math_PI / rings;
+ const double longitude_step = Math_TAU / radial_segments;
int face = 0;
-
- for (int i = 1; i <= rings; i++) {
- double lat0 = Math_PI * (-0.5 + (double)(i - 1) / rings);
- double z0 = Math::sin(lat0);
- double zr0 = Math::cos(lat0);
- double u0 = double(i - 1) / rings;
-
- double lat1 = Math_PI * (-0.5 + (double)i / rings);
- double z1 = Math::sin(lat1);
- double zr1 = Math::cos(lat1);
- double u1 = double(i) / rings;
-
- for (int j = radial_segments; j >= 1; j--) {
- double lng0 = 2 * Math_PI * (double)(j - 1) / radial_segments;
- double x0 = Math::cos(lng0);
- double y0 = Math::sin(lng0);
- double v0 = double(i - 1) / radial_segments;
-
- double lng1 = 2 * Math_PI * (double)(j) / radial_segments;
- double x1 = Math::cos(lng1);
- double y1 = Math::sin(lng1);
- double v1 = double(i) / radial_segments;
+ for (int i = 0; i < rings; i++) {
+ double latitude0 = latitude_step * i + Math_TAU / 4;
+ double cos0 = Math::cos(latitude0);
+ double sin0 = Math::sin(latitude0);
+ double v0 = double(i) / rings;
+
+ double latitude1 = latitude_step * (i + 1) + Math_TAU / 4;
+ double cos1 = Math::cos(latitude1);
+ double sin1 = Math::sin(latitude1);
+ double v1 = double(i + 1) / rings;
+
+ for (int j = 0; j < radial_segments; j++) {
+ double longitude0 = longitude_step * j;
+ // We give sin to X and cos to Z on purpose.
+ // This allows UVs to be CCW on +X so it maps to images well.
+ double x0 = Math::sin(longitude0);
+ double z0 = Math::cos(longitude0);
+ double u0 = double(j) / radial_segments;
+
+ double longitude1 = longitude_step * (j + 1);
+ double x1 = Math::sin(longitude1);
+ double z1 = Math::cos(longitude1);
+ double u1 = double(j + 1) / radial_segments;
Vector3 v[4] = {
- Vector3(x1 * zr0, z0, y1 * zr0) * radius,
- Vector3(x1 * zr1, z1, y1 * zr1) * radius,
- Vector3(x0 * zr1, z1, y0 * zr1) * radius,
- Vector3(x0 * zr0, z0, y0 * zr0) * radius
+ Vector3(x0 * cos0, sin0, z0 * cos0) * radius,
+ Vector3(x1 * cos0, sin0, z1 * cos0) * radius,
+ Vector3(x1 * cos1, sin1, z1 * cos1) * radius,
+ Vector3(x0 * cos1, sin1, z0 * cos1) * radius,
};
Vector2 u[4] = {
- Vector2(v1, u0),
- Vector2(v1, u1),
- Vector2(v0, u1),
- Vector2(v0, u0),
-
+ Vector2(u0, v0),
+ Vector2(u1, v0),
+ Vector2(u1, v1),
+ Vector2(u0, v1),
};
- if (i < rings) {
- //face 1
+ // Draw the first face, but skip this at the north pole (i == 0).
+ if (i > 0) {
facesw[face * 3 + 0] = v[0];
facesw[face * 3 + 1] = v[1];
facesw[face * 3 + 2] = v[2];
@@ -982,8 +988,8 @@ CSGBrush *CSGSphere3D::_build_brush() {
face++;
}
- if (i > 1) {
- //face 2
+ // Draw the second face, but skip this at the south pole (i == rings - 1).
+ if (i < rings - 1) {
facesw[face * 3 + 0] = v[2];
facesw[face * 3 + 1] = v[3];
facesw[face * 3 + 2] = v[0];
@@ -1030,15 +1036,14 @@ void CSGSphere3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
void CSGSphere3D::set_radius(const float p_radius) {
ERR_FAIL_COND(p_radius <= 0);
radius = p_radius;
_make_dirty();
- update_gizmo();
- _change_notify("radius");
+ update_gizmos();
}
float CSGSphere3D::get_radius() const {
@@ -1048,7 +1053,7 @@ float CSGSphere3D::get_radius() const {
void CSGSphere3D::set_radial_segments(const int p_radial_segments) {
radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int CSGSphere3D::get_radial_segments() const {
@@ -1058,7 +1063,7 @@ int CSGSphere3D::get_radial_segments() const {
void CSGSphere3D::set_rings(const int p_rings) {
rings = p_rings > 1 ? p_rings : 1;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int CSGSphere3D::get_rings() const {
@@ -1125,7 +1130,7 @@ CSGBrush *CSGBox3D::_build_brush() {
int face = 0;
- Vector3 vertex_mul(width * 0.5, height * 0.5, depth * 0.5);
+ Vector3 vertex_mul = size / 2;
{
for (int i = 0; i < 6; i++) {
@@ -1166,7 +1171,7 @@ CSGBrush *CSGBox3D::_build_brush() {
materialsw[face] = material;
face++;
- //face 1
+ //face 2
facesw[face * 3 + 0] = face_points[2] * vertex_mul;
facesw[face * 3 + 1] = face_points[3] * vertex_mul;
facesw[face * 3 + 2] = face_points[0] * vertex_mul;
@@ -1194,74 +1199,36 @@ CSGBrush *CSGBox3D::_build_brush() {
}
void CSGBox3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_width", "width"), &CSGBox3D::set_width);
- ClassDB::bind_method(D_METHOD("get_width"), &CSGBox3D::get_width);
-
- ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGBox3D::set_height);
- ClassDB::bind_method(D_METHOD("get_height"), &CSGBox3D::get_height);
-
- ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGBox3D::set_depth);
- ClassDB::bind_method(D_METHOD("get_depth"), &CSGBox3D::get_depth);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &CSGBox3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &CSGBox3D::get_size);
ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox3D::set_material);
ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_width", "get_width");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
-}
-
-void CSGBox3D::set_width(const float p_width) {
- width = p_width;
- _make_dirty();
- update_gizmo();
- _change_notify("width");
-}
-
-float CSGBox3D::get_width() const {
- return width;
-}
-
-void CSGBox3D::set_height(const float p_height) {
- height = p_height;
- _make_dirty();
- update_gizmo();
- _change_notify("height");
-}
-
-float CSGBox3D::get_height() const {
- return height;
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
-void CSGBox3D::set_depth(const float p_depth) {
- depth = p_depth;
+void CSGBox3D::set_size(const Vector3 &p_size) {
+ size = p_size;
_make_dirty();
- update_gizmo();
- _change_notify("depth");
+ update_gizmos();
}
-float CSGBox3D::get_depth() const {
- return depth;
+Vector3 CSGBox3D::get_size() const {
+ return size;
}
void CSGBox3D::set_material(const Ref<Material> &p_material) {
material = p_material;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
Ref<Material> CSGBox3D::get_material() const {
return material;
}
-CSGBox3D::CSGBox3D() {
- // defaults
- width = 2.0;
- height = 2.0;
- depth = 2.0;
-}
-
///////////////
CSGBrush *CSGCylinder3D::_build_brush() {
@@ -1303,8 +1270,8 @@ CSGBrush *CSGCylinder3D::_build_brush() {
float inc = float(i) / sides;
float inc_n = float((i + 1)) / sides;
- float ang = inc * Math_PI * 2.0;
- float ang_n = inc_n * Math_PI * 2.0;
+ float ang = inc * Math_TAU;
+ float ang_n = inc_n * Math_TAU;
Vector3 base(Math::cos(ang), 0, Math::sin(ang));
Vector3 base_n(Math::cos(ang_n), 0, Math::sin(ang_n));
@@ -1415,19 +1382,18 @@ void CSGCylinder3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder3D::set_smooth_faces);
ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder3D::get_smooth_faces);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cone"), "set_cone", "is_cone");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
void CSGCylinder3D::set_radius(const float p_radius) {
radius = p_radius;
_make_dirty();
- update_gizmo();
- _change_notify("radius");
+ update_gizmos();
}
float CSGCylinder3D::get_radius() const {
@@ -1437,8 +1403,7 @@ float CSGCylinder3D::get_radius() const {
void CSGCylinder3D::set_height(const float p_height) {
height = p_height;
_make_dirty();
- update_gizmo();
- _change_notify("height");
+ update_gizmos();
}
float CSGCylinder3D::get_height() const {
@@ -1449,7 +1414,7 @@ void CSGCylinder3D::set_sides(const int p_sides) {
ERR_FAIL_COND(p_sides < 3);
sides = p_sides;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int CSGCylinder3D::get_sides() const {
@@ -1459,7 +1424,7 @@ int CSGCylinder3D::get_sides() const {
void CSGCylinder3D::set_cone(const bool p_cone) {
cone = p_cone;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
bool CSGCylinder3D::is_cone() const {
@@ -1502,7 +1467,7 @@ CSGBrush *CSGTorus3D::_build_brush() {
float max_radius = outer_radius;
if (min_radius == max_radius) {
- return nullptr; //sorry, can't
+ return memnew(CSGBrush); //sorry, can't
}
if (min_radius > max_radius) {
@@ -1545,8 +1510,8 @@ CSGBrush *CSGTorus3D::_build_brush() {
float inci = float(i) / sides;
float inci_n = float((i + 1)) / sides;
- float angi = inci * Math_PI * 2.0;
- float angi_n = inci_n * Math_PI * 2.0;
+ float angi = inci * Math_TAU;
+ float angi_n = inci_n * Math_TAU;
Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
@@ -1555,8 +1520,8 @@ CSGBrush *CSGTorus3D::_build_brush() {
float incj = float(j) / ring_sides;
float incj_n = float((j + 1)) / ring_sides;
- float angj = incj * Math_PI * 2.0;
- float angj_n = incj_n * Math_PI * 2.0;
+ float angj = incj * Math_TAU;
+ float angj_n = incj_n * Math_TAU;
Vector2 normalj = Vector2(Math::cos(angj), Math::sin(angj)) * radius + Vector2(min_radius + radius, 0);
Vector2 normalj_n = Vector2(Math::cos(angj_n), Math::sin(angj_n)) * radius + Vector2(min_radius + radius, 0);
@@ -1636,19 +1601,18 @@ void CSGTorus3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus3D::set_smooth_faces);
ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus3D::get_smooth_faces);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_outer_radius", "get_outer_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_sides", "get_ring_sides");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
}
void CSGTorus3D::set_inner_radius(const float p_inner_radius) {
inner_radius = p_inner_radius;
_make_dirty();
- update_gizmo();
- _change_notify("inner_radius");
+ update_gizmos();
}
float CSGTorus3D::get_inner_radius() const {
@@ -1658,8 +1622,7 @@ float CSGTorus3D::get_inner_radius() const {
void CSGTorus3D::set_outer_radius(const float p_outer_radius) {
outer_radius = p_outer_radius;
_make_dirty();
- update_gizmo();
- _change_notify("outer_radius");
+ update_gizmos();
}
float CSGTorus3D::get_outer_radius() const {
@@ -1670,7 +1633,7 @@ void CSGTorus3D::set_sides(const int p_sides) {
ERR_FAIL_COND(p_sides < 3);
sides = p_sides;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int CSGTorus3D::get_sides() const {
@@ -1681,7 +1644,7 @@ void CSGTorus3D::set_ring_sides(const int p_ring_sides) {
ERR_FAIL_COND(p_ring_sides < 3);
ring_sides = p_ring_sides;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int CSGTorus3D::get_ring_sides() const {
@@ -1718,110 +1681,86 @@ CSGTorus3D::CSGTorus3D() {
///////////////
CSGBrush *CSGPolygon3D::_build_brush() {
- // set our bounding box
+ CSGBrush *brush = memnew(CSGBrush);
if (polygon.size() < 3) {
- return nullptr;
+ return brush;
}
- Vector<Point2> final_polygon = polygon;
-
- if (Triangulate::get_area(final_polygon) > 0) {
- final_polygon.invert();
+ // Triangulate polygon shape.
+ Vector<Point2> shape_polygon = polygon;
+ if (Triangulate::get_area(shape_polygon) > 0) {
+ shape_polygon.reverse();
}
-
- Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon);
-
- if (triangles.size() < 3) {
- return nullptr;
+ 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");
+
+ // Get polygon enclosing Rect2.
+ Rect2 shape_rect(shape_polygon[0], Vector2());
+ for (int i = 1; i < shape_sides; i++) {
+ shape_rect.expand_to(shape_polygon[i]);
}
- Path3D *path = nullptr;
+ // If MODE_PATH, check if curve has changed.
Ref<Curve3D> curve;
-
- // get bounds for our polygon
- Vector2 final_polygon_min;
- Vector2 final_polygon_max;
- for (int i = 0; i < final_polygon.size(); i++) {
- Vector2 p = final_polygon[i];
- if (i == 0) {
- final_polygon_min = p;
- final_polygon_max = final_polygon_min;
- } else {
- if (p.x < final_polygon_min.x) {
- final_polygon_min.x = p.x;
- }
- if (p.y < final_polygon_min.y) {
- final_polygon_min.y = p.y;
- }
-
- if (p.x > final_polygon_max.x) {
- final_polygon_max.x = p.x;
+ if (mode == MODE_PATH) {
+ Path3D *current_path = Object::cast_to<Path3D>(get_node_or_null(path_node));
+ if (path != current_path) {
+ if (path) {
+ path->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
}
- if (p.y > final_polygon_max.y) {
- final_polygon_max.y = p.y;
+ path = current_path;
+ if (path) {
+ path->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
}
}
- }
- Vector2 final_polygon_size = final_polygon_max - final_polygon_min;
- if (mode == MODE_PATH) {
- if (!has_node(path_node)) {
- return nullptr;
- }
- Node *n = get_node(path_node);
- if (!n) {
- return nullptr;
- }
- path = Object::cast_to<Path3D>(n);
if (!path) {
- return nullptr;
+ return brush;
}
- if (path != path_cache) {
- if (path_cache) {
- path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
- path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
- }
-
- path_cache = path;
-
- path_cache->connect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
- path_cache->connect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
- }
curve = path->get_curve();
- if (curve.is_null()) {
- return nullptr;
- }
- if (curve->get_baked_length() <= 0) {
- return nullptr;
+ if (curve.is_null() || curve->get_point_count() < 2) {
+ return brush;
}
}
- CSGBrush *brush = memnew(CSGBrush);
-
- int face_count = 0;
+ // Calculate the number extrusions, ends and faces.
+ int extrusions = 0;
+ int extrusion_face_count = shape_sides * 2;
+ int end_count = 0;
+ int shape_face_count = shape_faces.size() / 3;
+ real_t curve_length = 1.0;
switch (mode) {
case MODE_DEPTH:
- face_count = triangles.size() * 2 / 3 + (final_polygon.size()) * 2;
+ extrusions = 1;
+ end_count = 2;
break;
case MODE_SPIN:
- face_count = (spin_degrees < 360 ? triangles.size() * 2 / 3 : 0) + (final_polygon.size()) * 2 * spin_sides;
+ extrusions = spin_sides;
+ if (spin_degrees < 360) {
+ end_count = 2;
+ }
break;
case MODE_PATH: {
- float bl = curve->get_baked_length();
- int splits = MAX(2, Math::ceil(bl / path_interval));
- if (path_joined) {
- face_count = splits * final_polygon.size() * 2;
+ curve_length = curve->get_baked_length();
+ if (path_interval_type == PATH_INTERVAL_DISTANCE) {
+ extrusions = MAX(1, Math::ceil(curve_length / path_interval)) + 1;
} else {
- face_count = triangles.size() * 2 / 3 + splits * final_polygon.size() * 2;
+ extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval);
+ }
+ if (!path_joined) {
+ end_count = 2;
+ extrusions -= 1;
}
} break;
}
+ int face_count = extrusions * extrusion_face_count + end_count * shape_face_count;
- bool invert_val = is_inverting_faces();
+ // Intialize variables used to create the mesh.
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1832,12 +1771,11 @@ CSGBrush *CSGPolygon3D::_build_brush() {
faces.resize(face_count * 3);
uvs.resize(face_count * 3);
-
smooth.resize(face_count);
materials.resize(face_count);
invert.resize(face_count);
+ int faces_removed = 0;
- AABB aabb; //must be computed
{
Vector3 *facesw = faces.ptrw();
Vector2 *uvsw = uvs.ptrw();
@@ -1846,346 +1784,234 @@ CSGBrush *CSGPolygon3D::_build_brush() {
bool *invertw = invert.ptrw();
int face = 0;
+ Transform3D base_xform;
+ Transform3D current_xform;
+ Transform3D previous_xform;
+ Transform3D previous_previous_xform;
+ double u_step = 1.0 / extrusions;
+ if (path_u_distance > 0.0) {
+ u_step *= curve_length / path_u_distance;
+ }
+ double v_step = 1.0 / shape_sides;
+ double spin_step = Math::deg2rad(spin_degrees / spin_sides);
+ double extrusion_step = 1.0 / extrusions;
+ if (mode == MODE_PATH) {
+ if (path_joined) {
+ extrusion_step = 1.0 / (extrusions - 1);
+ }
+ extrusion_step *= curve_length;
+ }
- switch (mode) {
- case MODE_DEPTH: {
- //add triangles, front and back
- for (int i = 0; i < 2; i++) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, i == 0 ? 1 : 2, i == 0 ? 2 : 1 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- if (i == 0) {
- v.z -= depth;
- }
- facesw[face * 3 + k] = v;
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- if (i == 0) {
- uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
- }
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
-
- //add triangles for depth
- for (int i = 0; i < final_polygon.size(); i++) {
- int i_n = (i + 1) % final_polygon.size();
-
- Vector3 v[4] = {
- Vector3(final_polygon[i].x, final_polygon[i].y, -depth),
- Vector3(final_polygon[i_n].x, final_polygon[i_n].y, -depth),
- Vector3(final_polygon[i_n].x, final_polygon[i_n].y, 0),
- Vector3(final_polygon[i].x, final_polygon[i].y, 0),
- };
-
- Vector2 u[4] = {
- Vector2(0, 0),
- Vector2(0, 1),
- Vector2(1, 1),
- Vector2(1, 0)
- };
-
- // face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[1];
- facesw[face * 3 + 2] = v[2];
-
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[1];
- uvsw[face * 3 + 2] = u[2];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
+ if (mode == MODE_PATH) {
+ if (!path_local) {
+ base_xform = path->get_global_transform();
+ }
- face++;
+ Vector3 current_point = curve->interpolate_baked(0);
+ Vector3 next_point = curve->interpolate_baked(extrusion_step);
+ Vector3 current_up = Vector3(0, 1, 0);
+ Vector3 direction = next_point - current_point;
- // face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[3];
- facesw[face * 3 + 2] = v[0];
+ if (path_joined) {
+ Vector3 last_point = curve->interpolate_baked(curve->get_baked_length());
+ direction = next_point - last_point;
+ }
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[3];
- uvsw[face * 3 + 2] = u[0];
+ switch (path_rotation) {
+ case PATH_ROTATION_POLYGON:
+ direction = Vector3(0, 0, -1);
+ break;
+ case PATH_ROTATION_PATH:
+ break;
+ case PATH_ROTATION_PATH_FOLLOW:
+ current_up = curve->interpolate_baked_up_vector(0);
+ break;
+ }
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
+ Transform3D facing = Transform3D().looking_at(direction, current_up);
+ current_xform = base_xform.translated(current_point) * facing;
+ }
- face++;
+ // Create the mesh.
+ if (end_count > 0) {
+ // Add front end face.
+ for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
+ for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
+ // We need to reverse the rotation of the shape face vertices.
+ int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx];
+ Point2 p = shape_polygon[index];
+ Point2 uv = (p - shape_rect.position) / shape_rect.size;
+
+ // Use the left side of the bottom half of the y-inverted texture.
+ uv.x = uv.x / 2;
+ uv.y = 1 - (uv.y / 2);
+
+ facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
+ uvsw[face * 3 + face_vertex_idx] = uv;
}
- } break;
- case MODE_SPIN: {
- for (int i = 0; i < spin_sides; i++) {
- float inci = float(i) / spin_sides;
- float inci_n = float((i + 1)) / spin_sides;
-
- float angi = -(inci * spin_degrees / 360.0) * Math_PI * 2.0;
- float angi_n = -(inci_n * spin_degrees / 360.0) * Math_PI * 2.0;
-
- Vector3 normali = Vector3(Math::cos(angi), 0, Math::sin(angi));
- Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n));
-
- //add triangles for depth
- for (int j = 0; j < final_polygon.size(); j++) {
- int j_n = (j + 1) % final_polygon.size();
-
- Vector3 v[4] = {
- Vector3(normali.x * final_polygon[j].x, final_polygon[j].y, normali.z * final_polygon[j].x),
- Vector3(normali.x * final_polygon[j_n].x, final_polygon[j_n].y, normali.z * final_polygon[j_n].x),
- Vector3(normali_n.x * final_polygon[j_n].x, final_polygon[j_n].y, normali_n.z * final_polygon[j_n].x),
- Vector3(normali_n.x * final_polygon[j].x, final_polygon[j].y, normali_n.z * final_polygon[j].x),
- };
-
- Vector2 u[4] = {
- Vector2(0, 0),
- Vector2(0, 1),
- Vector2(1, 1),
- Vector2(1, 0)
- };
-
- // face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[2];
- facesw[face * 3 + 2] = v[1];
-
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[2];
- uvsw[face * 3 + 2] = u[1];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
-
- face++;
-
- // face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[0];
- facesw[face * 3 + 2] = v[3];
-
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[0];
- uvsw[face * 3 + 2] = u[3];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
-
- face++;
- }
-
- if (i == 0 && spin_degrees < 360) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 2, 1 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- facesw[face * 3 + k] = v;
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
+ smoothw[face] = false;
+ materialsw[face] = material;
+ invertw[face] = invert_faces;
+ face++;
+ }
+ }
- if (i == spin_sides - 1 && spin_degrees < 360) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 1, 2 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(normali_n.x * p.x, p.y, normali_n.z * p.x);
- facesw[face * 3 + k] = v;
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
+ real_t angle_simplify_dot = Math::cos(Math::deg2rad(path_simplify_angle));
+ Vector3 previous_simplify_dir = Vector3(0, 0, 0);
+ int faces_combined = 0;
+
+ // Add extrusion faces.
+ for (int x0 = 0; x0 < extrusions; x0++) {
+ previous_previous_xform = previous_xform;
+ previous_xform = current_xform;
+
+ switch (mode) {
+ case MODE_DEPTH: {
+ current_xform.translate(Vector3(0, 0, -depth));
+ } break;
+ case MODE_SPIN: {
+ current_xform.rotate(Vector3(0, 1, 0), spin_step);
+ } break;
+ case MODE_PATH: {
+ double previous_offset = x0 * extrusion_step;
+ double current_offset = (x0 + 1) * extrusion_step;
+ double next_offset = (x0 + 2) * extrusion_step;
+ if (x0 == extrusions - 1) {
+ if (path_joined) {
+ current_offset = 0;
+ next_offset = extrusion_step;
+ } else {
+ next_offset = current_offset;
}
}
- }
- } break;
- case MODE_PATH: {
- float bl = curve->get_baked_length();
- int splits = MAX(2, Math::ceil(bl / path_interval));
- float u1 = 0.0;
- float u2 = path_continuous_u ? 0.0 : 1.0;
-
- Transform path_to_this;
- if (!path_local) {
- // center on paths origin
- path_to_this = get_global_transform().affine_inverse() * path->get_global_transform();
- }
-
- Transform prev_xf;
-
- Vector3 lookat_dir;
-
- if (path_rotation == PATH_ROTATION_POLYGON) {
- lookat_dir = (path->get_global_transform().affine_inverse() * get_global_transform()).xform(Vector3(0, 0, -1));
- } else {
- Vector3 p1, p2;
- p1 = curve->interpolate_baked(0);
- p2 = curve->interpolate_baked(0.1);
- lookat_dir = (p2 - p1).normalized();
- }
-
- for (int i = 0; i <= splits; i++) {
- float ofs = i * path_interval;
- if (ofs > bl) {
- ofs = bl;
- }
- if (i == splits && path_joined) {
- ofs = 0.0;
- }
-
- Transform xf;
- xf.origin = curve->interpolate_baked(ofs);
-
- Vector3 local_dir;
-
- if (path_rotation == PATH_ROTATION_PATH_FOLLOW && ofs > 0) {
- //before end
- Vector3 p1 = curve->interpolate_baked(ofs - 0.1);
- Vector3 p2 = curve->interpolate_baked(ofs);
- local_dir = (p2 - p1).normalized();
+ Vector3 previous_point = curve->interpolate_baked(previous_offset);
+ Vector3 current_point = curve->interpolate_baked(current_offset);
+ Vector3 next_point = curve->interpolate_baked(next_offset);
+ Vector3 current_up = Vector3(0, 1, 0);
+ Vector3 direction = next_point - previous_point;
+ Vector3 current_dir = (current_point - previous_point).normalized();
+
+ // If the angles are similar, remove the previous face and replace it with this one.
+ if (path_simplify_angle > 0.0 && x0 > 0 && previous_simplify_dir.dot(current_dir) > angle_simplify_dot) {
+ faces_combined += 1;
+ previous_xform = previous_previous_xform;
+ face -= extrusion_face_count;
+ faces_removed += extrusion_face_count;
} else {
- local_dir = lookat_dir;
+ faces_combined = 0;
+ previous_simplify_dir = current_dir;
}
- xf = xf.looking_at(xf.origin + local_dir, Vector3(0, 1, 0));
- Basis rot(Vector3(0, 0, 1), curve->interpolate_baked_tilt(ofs));
-
- xf = xf * rot; //post mult
+ switch (path_rotation) {
+ case PATH_ROTATION_POLYGON:
+ direction = Vector3(0, 0, -1);
+ break;
+ case PATH_ROTATION_PATH:
+ break;
+ case PATH_ROTATION_PATH_FOLLOW:
+ current_up = curve->interpolate_baked_up_vector(current_offset);
+ break;
+ }
- xf = path_to_this * xf;
+ Transform3D facing = Transform3D().looking_at(direction, current_up);
+ current_xform = base_xform.translated(current_point) * facing;
+ } break;
+ }
- if (i > 0) {
- if (path_continuous_u) {
- u1 = u2;
- u2 += (prev_xf.origin - xf.origin).length();
- };
+ double u0 = (x0 - faces_combined) * u_step;
+ double u1 = ((x0 + 1) * u_step);
+ if (mode == MODE_PATH && !path_continuous_u) {
+ u0 = 0.0;
+ u1 = 1.0;
+ }
- //put triangles where they belong
- //add triangles for depth
- for (int j = 0; j < final_polygon.size(); j++) {
- int j_n = (j + 1) % final_polygon.size();
+ for (int y0 = 0; y0 < shape_sides; y0++) {
+ int y1 = (y0 + 1) % shape_sides;
+ // Use the top half of the texture.
+ double v0 = (y0 * v_step) / 2;
+ double v1 = ((y0 + 1) * v_step) / 2;
- Vector3 v[4] = {
- prev_xf.xform(Vector3(final_polygon[j].x, final_polygon[j].y, 0)),
- prev_xf.xform(Vector3(final_polygon[j_n].x, final_polygon[j_n].y, 0)),
- xf.xform(Vector3(final_polygon[j_n].x, final_polygon[j_n].y, 0)),
- xf.xform(Vector3(final_polygon[j].x, final_polygon[j].y, 0)),
- };
+ Vector3 v[4] = {
+ previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
+ current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
+ current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
+ previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
+ };
- Vector2 u[4] = {
- Vector2(u1, 1),
- Vector2(u1, 0),
- Vector2(u2, 0),
- Vector2(u2, 1)
- };
+ Vector2 u[4] = {
+ Vector2(u0, v0),
+ Vector2(u1, v0),
+ Vector2(u1, v1),
+ Vector2(u0, v1),
+ };
- // face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[1];
- facesw[face * 3 + 2] = v[2];
+ // Face 1
+ facesw[face * 3 + 0] = v[0];
+ facesw[face * 3 + 1] = v[1];
+ facesw[face * 3 + 2] = v[2];
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[1];
- uvsw[face * 3 + 2] = u[2];
+ uvsw[face * 3 + 0] = u[0];
+ uvsw[face * 3 + 1] = u[1];
+ uvsw[face * 3 + 2] = u[2];
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
+ smoothw[face] = smooth_faces;
+ invertw[face] = invert_faces;
+ materialsw[face] = material;
- face++;
+ face++;
- // face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[3];
- facesw[face * 3 + 2] = v[0];
+ // Face 2
+ facesw[face * 3 + 0] = v[2];
+ facesw[face * 3 + 1] = v[3];
+ facesw[face * 3 + 2] = v[0];
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[3];
- uvsw[face * 3 + 2] = u[0];
+ uvsw[face * 3 + 0] = u[2];
+ uvsw[face * 3 + 1] = u[3];
+ uvsw[face * 3 + 2] = u[0];
- smoothw[face] = smooth_faces;
- invertw[face] = invert_val;
- materialsw[face] = material;
+ smoothw[face] = smooth_faces;
+ invertw[face] = invert_faces;
+ materialsw[face] = material;
- face++;
- }
- }
+ face++;
+ }
+ }
- if (i == 0 && !path_joined) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 1, 2 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- facesw[face * 3 + k] = xf.xform(v);
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
+ if (end_count > 1) {
+ // Add back end face.
+ for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
+ for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
+ int index = shape_faces[face_idx * 3 + face_vertex_idx];
+ Point2 p = shape_polygon[index];
+ Point2 uv = (p - shape_rect.position) / shape_rect.size;
- if (i == splits && !path_joined) {
- for (int j = 0; j < triangles.size(); j += 3) {
- for (int k = 0; k < 3; k++) {
- int src[3] = { 0, 2, 1 };
- Vector2 p = final_polygon[triangles[j + src[k]]];
- Vector3 v = Vector3(p.x, p.y, 0);
- facesw[face * 3 + k] = xf.xform(v);
- uvsw[face * 3 + k] = (p - final_polygon_min) / final_polygon_size;
- uvsw[face * 3 + k].x = 1.0 - uvsw[face * 3 + k].x; /* flip x */
- }
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_val;
- face++;
- }
- }
+ // Use the x-inverted ride side of the bottom half of the y-inverted texture.
+ uv.x = 1 - uv.x / 2;
+ uv.y = 1 - (uv.y / 2);
- prev_xf = xf;
+ facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
+ uvsw[face * 3 + face_vertex_idx] = uv;
}
- } break;
+ smoothw[face] = false;
+ materialsw[face] = material;
+ invertw[face] = invert_faces;
+ face++;
+ }
}
- if (face != face_count) {
- ERR_PRINT("Face mismatch bug! fix code");
- }
- for (int i = 0; i < face_count * 3; i++) {
- if (i == 0) {
- aabb.position = facesw[i];
- } else {
- aabb.expand_to(facesw[i]);
- }
+ face_count -= faces_removed;
+ ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
+ }
- // invert UVs on the Y-axis OpenGL = upside down
- uvsw[i].y = 1.0 - uvsw[i].y;
- }
+ if (faces_removed > 0) {
+ faces.resize(face_count * 3);
+ uvs.resize(face_count * 3);
+ smooth.resize(face_count);
+ materials.resize(face_count);
+ invert.resize(face_count);
}
brush->build_from_faces(faces, uvs, smooth, materials, invert);
@@ -2195,23 +2021,23 @@ CSGBrush *CSGPolygon3D::_build_brush() {
void CSGPolygon3D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
- if (path_cache) {
- path_cache->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
- path_cache->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
- path_cache = nullptr;
+ if (path) {
+ path->disconnect("tree_exited", callable_mp(this, &CSGPolygon3D::_path_exited));
+ path->disconnect("curve_changed", callable_mp(this, &CSGPolygon3D::_path_changed));
+ path = nullptr;
}
}
}
void CSGPolygon3D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("spin") && mode != MODE_SPIN) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name.begins_with("path") && mode != MODE_PATH) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
if (property.name == "depth" && mode != MODE_DEPTH) {
- property.usage = 0;
+ property.usage = PROPERTY_USAGE_NONE;
}
CSGShape3D::_validate_property(property);
@@ -2219,11 +2045,11 @@ void CSGPolygon3D::_validate_property(PropertyInfo &property) const {
void CSGPolygon3D::_path_changed() {
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
void CSGPolygon3D::_path_exited() {
- path_cache = nullptr;
+ path = nullptr;
}
void CSGPolygon3D::_bind_methods() {
@@ -2245,10 +2071,16 @@ void CSGPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon3D::set_path_node);
ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon3D::get_path_node);
- ClassDB::bind_method(D_METHOD("set_path_interval", "distance"), &CSGPolygon3D::set_path_interval);
+ ClassDB::bind_method(D_METHOD("set_path_interval_type", "interval_type"), &CSGPolygon3D::set_path_interval_type);
+ ClassDB::bind_method(D_METHOD("get_path_interval_type"), &CSGPolygon3D::get_path_interval_type);
+
+ ClassDB::bind_method(D_METHOD("set_path_interval", "interval"), &CSGPolygon3D::set_path_interval);
ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon3D::get_path_interval);
- ClassDB::bind_method(D_METHOD("set_path_rotation", "mode"), &CSGPolygon3D::set_path_rotation);
+ ClassDB::bind_method(D_METHOD("set_path_simplify_angle", "degrees"), &CSGPolygon3D::set_path_simplify_angle);
+ ClassDB::bind_method(D_METHOD("get_path_simplify_angle"), &CSGPolygon3D::get_path_simplify_angle);
+
+ ClassDB::bind_method(D_METHOD("set_path_rotation", "path_rotation"), &CSGPolygon3D::set_path_rotation);
ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon3D::get_path_rotation);
ClassDB::bind_method(D_METHOD("set_path_local", "enable"), &CSGPolygon3D::set_path_local);
@@ -2257,6 +2089,9 @@ void CSGPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon3D::set_path_continuous_u);
ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon3D::is_path_continuous_u);
+ ClassDB::bind_method(D_METHOD("set_path_u_distance", "distance"), &CSGPolygon3D::set_path_u_distance);
+ ClassDB::bind_method(D_METHOD("get_path_u_distance"), &CSGPolygon3D::get_path_u_distance);
+
ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon3D::set_path_joined);
ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon3D::is_path_joined);
@@ -2271,17 +2106,20 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.01,100.0,0.01,or_greater,exp"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path"), "set_path_node", "get_path_node");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_interval_type", PROPERTY_HINT_ENUM, "Distance,Subdivide"), "set_path_interval_type", "get_path_interval_type");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.01,1.0,0.01,exp,or_greater"), "set_path_interval", "get_path_interval");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1,exp"), "set_path_simplify_angle", "get_path_simplify_angle");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_u_distance", PROPERTY_HINT_RANGE, "0.0,10.0,0.01,or_greater"), "set_path_u_distance", "get_path_u_distance");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
BIND_ENUM_CONSTANT(MODE_DEPTH);
BIND_ENUM_CONSTANT(MODE_SPIN);
@@ -2290,12 +2128,15 @@ void CSGPolygon3D::_bind_methods() {
BIND_ENUM_CONSTANT(PATH_ROTATION_POLYGON);
BIND_ENUM_CONSTANT(PATH_ROTATION_PATH);
BIND_ENUM_CONSTANT(PATH_ROTATION_PATH_FOLLOW);
+
+ BIND_ENUM_CONSTANT(PATH_INTERVAL_DISTANCE);
+ BIND_ENUM_CONSTANT(PATH_INTERVAL_SUBDIVIDE);
}
void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) {
polygon = p_polygon;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
Vector<Vector2> CSGPolygon3D::get_polygon() const {
@@ -2305,8 +2146,8 @@ Vector<Vector2> CSGPolygon3D::get_polygon() const {
void CSGPolygon3D::set_mode(Mode p_mode) {
mode = p_mode;
_make_dirty();
- update_gizmo();
- _change_notify();
+ update_gizmos();
+ notify_property_list_changed();
}
CSGPolygon3D::Mode CSGPolygon3D::get_mode() const {
@@ -2317,7 +2158,7 @@ void CSGPolygon3D::set_depth(const float p_depth) {
ERR_FAIL_COND(p_depth < 0.001);
depth = p_depth;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
float CSGPolygon3D::get_depth() const {
@@ -2333,22 +2174,32 @@ bool CSGPolygon3D::is_path_continuous_u() const {
return path_continuous_u;
}
+void CSGPolygon3D::set_path_u_distance(real_t p_path_u_distance) {
+ path_u_distance = p_path_u_distance;
+ _make_dirty();
+ update_gizmos();
+}
+
+real_t CSGPolygon3D::get_path_u_distance() const {
+ return path_u_distance;
+}
+
void CSGPolygon3D::set_spin_degrees(const float p_spin_degrees) {
ERR_FAIL_COND(p_spin_degrees < 0.01 || p_spin_degrees > 360);
spin_degrees = p_spin_degrees;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
float CSGPolygon3D::get_spin_degrees() const {
return spin_degrees;
}
-void CSGPolygon3D::set_spin_sides(const int p_spin_sides) {
+void CSGPolygon3D::set_spin_sides(int p_spin_sides) {
ERR_FAIL_COND(p_spin_sides < 3);
spin_sides = p_spin_sides;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
int CSGPolygon3D::get_spin_sides() const {
@@ -2358,28 +2209,47 @@ int CSGPolygon3D::get_spin_sides() const {
void CSGPolygon3D::set_path_node(const NodePath &p_path) {
path_node = p_path;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
NodePath CSGPolygon3D::get_path_node() const {
return path_node;
}
+void CSGPolygon3D::set_path_interval_type(PathIntervalType p_interval_type) {
+ path_interval_type = p_interval_type;
+ _make_dirty();
+ update_gizmos();
+}
+
+CSGPolygon3D::PathIntervalType CSGPolygon3D::get_path_interval_type() const {
+ return path_interval_type;
+}
+
void CSGPolygon3D::set_path_interval(float p_interval) {
- ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001.");
path_interval = p_interval;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
float CSGPolygon3D::get_path_interval() const {
return path_interval;
}
+void CSGPolygon3D::set_path_simplify_angle(float p_angle) {
+ path_simplify_angle = p_angle;
+ _make_dirty();
+ update_gizmos();
+}
+
+float CSGPolygon3D::get_path_simplify_angle() const {
+ return path_simplify_angle;
+}
+
void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) {
path_rotation = p_rotation;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
CSGPolygon3D::PathRotation CSGPolygon3D::get_path_rotation() const {
@@ -2389,7 +2259,7 @@ CSGPolygon3D::PathRotation CSGPolygon3D::get_path_rotation() const {
void CSGPolygon3D::set_path_local(bool p_enable) {
path_local = p_enable;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
bool CSGPolygon3D::is_path_local() const {
@@ -2399,7 +2269,7 @@ bool CSGPolygon3D::is_path_local() const {
void CSGPolygon3D::set_path_joined(bool p_enable) {
path_joined = p_enable;
_make_dirty();
- update_gizmo();
+ update_gizmos();
}
bool CSGPolygon3D::is_path_joined() const {
@@ -2443,10 +2313,13 @@ CSGPolygon3D::CSGPolygon3D() {
spin_degrees = 360;
spin_sides = 8;
smooth_faces = false;
- path_interval = 1;
- path_rotation = PATH_ROTATION_PATH;
+ path_interval_type = PATH_INTERVAL_DISTANCE;
+ path_interval = 1.0;
+ path_simplify_angle = 0.0;
+ path_rotation = PATH_ROTATION_PATH_FOLLOW;
path_local = false;
- path_continuous_u = false;
+ path_continuous_u = true;
+ path_u_distance = 1.0;
path_joined = false;
- path_cache = nullptr;
+ path = nullptr;
}
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index d93693f145..c85cce776b 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,7 @@
#define CSGJS_HEADER_ONLY
#include "csg.h"
+#include "scene/3d/path_3d.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/resources/concave_polygon_shape_3d.h"
#include "thirdparty/misc/mikktspace.h"
@@ -50,23 +51,23 @@ public:
};
private:
- Operation operation;
- CSGShape3D *parent;
+ Operation operation = OPERATION_UNION;
+ CSGShape3D *parent = nullptr;
- CSGBrush *brush;
+ CSGBrush *brush = nullptr;
AABB node_aabb;
- bool dirty;
- float snap;
+ bool dirty = false;
+ float snap = 0.001;
- bool use_collision;
- uint32_t collision_layer;
- uint32_t collision_mask;
+ bool use_collision = false;
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
Ref<ConcavePolygonShape3D> root_collision_shape;
RID root_collision_instance;
- bool calculate_tangents;
+ bool calculate_tangents = true;
Ref<ArrayMesh> root_mesh;
@@ -83,14 +84,14 @@ private:
Vector<Vector3> vertices;
Vector<Vector3> normals;
Vector<Vector2> uvs;
- Vector<float> tans;
+ Vector<real_t> tans;
Ref<Material> material;
- int last_added;
+ int last_added = 0;
- Vector3 *verticesw;
- Vector3 *normalsw;
- Vector2 *uvsw;
- float *tansw;
+ Vector3 *verticesw = nullptr;
+ Vector3 *normalsw = nullptr;
+ Vector2 *uvsw = nullptr;
+ real_t *tansw = nullptr;
};
//mikktspace callbacks
@@ -136,11 +137,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_snap(float p_snap);
float get_snap() const;
@@ -168,10 +169,8 @@ public:
class CSGPrimitive3D : public CSGShape3D {
GDCLASS(CSGPrimitive3D, CSGShape3D);
-private:
- bool invert_faces;
-
protected:
+ bool invert_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();
@@ -240,27 +239,19 @@ class CSGBox3D : public CSGPrimitive3D {
virtual CSGBrush *_build_brush() override;
Ref<Material> material;
- float width;
- float height;
- float depth;
+ Vector3 size = Vector3(2, 2, 2);
protected:
static void _bind_methods();
public:
- void set_width(const float p_width);
- float get_width() const;
-
- void set_height(const float p_height);
- float get_height() const;
-
- void set_depth(const float p_depth);
- float get_depth() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_material(const Ref<Material> &p_material);
Ref<Material> get_material() const;
- CSGBox3D();
+ CSGBox3D() {}
};
class CSGCylinder3D : public CSGPrimitive3D {
@@ -345,6 +336,11 @@ public:
MODE_PATH
};
+ enum PathIntervalType {
+ PATH_INTERVAL_DISTANCE,
+ PATH_INTERVAL_SUBDIVIDE
+ };
+
enum PathRotation {
PATH_ROTATION_POLYGON,
PATH_ROTATION_PATH,
@@ -365,14 +361,17 @@ private:
int spin_sides;
NodePath path_node;
+ PathIntervalType path_interval_type;
float path_interval;
+ float path_simplify_angle;
PathRotation path_rotation;
bool path_local;
- Node *path_cache;
+ Path3D *path;
bool smooth_faces;
bool path_continuous_u;
+ real_t path_u_distance;
bool path_joined;
bool _is_editable_3d_polygon() const;
@@ -405,9 +404,15 @@ public:
void set_path_node(const NodePath &p_path);
NodePath get_path_node() const;
+ void set_path_interval_type(PathIntervalType p_interval_type);
+ PathIntervalType get_path_interval_type() const;
+
void set_path_interval(float p_interval);
float get_path_interval() const;
+ void set_path_simplify_angle(float p_angle);
+ float get_path_simplify_angle() const;
+
void set_path_rotation(PathRotation p_rotation);
PathRotation get_path_rotation() const;
@@ -417,6 +422,9 @@ public:
void set_path_continuous_u(bool p_enable);
bool is_path_continuous_u() const;
+ void set_path_u_distance(real_t p_path_u_distance);
+ real_t get_path_u_distance() const;
+
void set_path_joined(bool p_enable);
bool is_path_joined() const;
@@ -431,5 +439,6 @@ public:
VARIANT_ENUM_CAST(CSGPolygon3D::Mode)
VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation)
+VARIANT_ENUM_CAST(CSGPolygon3D::PathIntervalType)
#endif // CSG_SHAPE_H
diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml
index 492bf68c44..d64e58ae4d 100644
--- a/modules/csg/doc_classes/CSGBox3D.xml
+++ b/modules/csg/doc_classes/CSGBox3D.xml
@@ -8,22 +8,12 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
- <member name="depth" type="float" setter="set_depth" getter="get_depth" default="2.0">
- Depth of the box measured from the center of the box.
- </member>
- <member name="height" type="float" setter="set_height" getter="get_height" default="2.0">
- Height of the box measured from the center of the box.
- </member>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the box.
</member>
- <member name="width" type="float" setter="set_width" getter="get_width" default="2.0">
- Width of the box measured from the center of the box.
+ <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)">
+ The box's width, height and depth.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml
index b55111eee4..422c5d35b7 100644
--- a/modules/csg/doc_classes/CSGCombiner3D.xml
+++ b/modules/csg/doc_classes/CSGCombiner3D.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGCylinder3D.xml b/modules/csg/doc_classes/CSGCylinder3D.xml
index bfd2a5d5f2..40e989bfb3 100644
--- a/modules/csg/doc_classes/CSGCylinder3D.xml
+++ b/modules/csg/doc_classes/CSGCylinder3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<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.
@@ -30,6 +28,4 @@
If [code]true[/code] the normals of the cylinder are set to give a smooth effect making the cylinder seem rounded. If [code]false[/code] the cylinder will have a flat shaded look.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 1bab8f4ee9..2810343139 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -4,20 +4,17 @@
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 then 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.
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
The [Material] used in drawing the CSG shape.
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
The [Mesh] resource to use as a CSG shape.
+ [b]Note:[/b] When using an [ArrayMesh], avoid meshes with vertex normals unless a flat shader is required. By default, CSGMesh will ignore the mesh's vertex normals and use a smooth shader calculated using the faces' normals. If a flat shader is required, ensure that all faces' vertex normals are parallel.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml
index c55fa0983e..ecbb7962d1 100644
--- a/modules/csg/doc_classes/CSGPolygon3D.xml
+++ b/modules/csg/doc_classes/CSGPolygon3D.xml
@@ -4,71 +4,86 @@
Extrudes a 2D polygon shape to create a 3D mesh.
</brief_description>
<description>
- This node takes a 2D polygon shape and extrudes it to create a 3D mesh.
+ An array of 2D points is extruded to quickly and easily create a variety of 3D meshes.
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
- Extrusion depth when [member mode] is [constant MODE_DEPTH].
+ When [member mode] is [constant MODE_DEPTH], the depth of the extrusion.
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
- Material to use for the resulting mesh.
+ Material to use for the resulting mesh. The UV maps the top half of the material to the extruded shape (U along the length of the extrusions and V around the outline of the [member polygon]), the bottom-left quarter to the front end face, and the bottom-right quarter to the back end face.
</member>
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon3D.Mode" default="0">
- Extrusion mode.
+ The [member mode] used to extrude the [member polygon].
</member>
<member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u">
- If [code]true[/code] the u component of our uv will continuously increase in unison with the distance traveled along our path when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], by default, the top half of the [member material] is stretched along the entire length of the extruded shape. If [code]false[/code] the top half of the material is repeated every step of the extrusion.
</member>
<member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval">
- Interval at which a new extrusion slice is added along the path when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], the path interval or ratio of path points to extrusions.
+ </member>
+ <member name="path_interval_type" type="int" setter="set_path_interval_type" getter="get_path_interval_type" enum="CSGPolygon3D.PathIntervalType">
+ When [member mode] is [constant MODE_PATH], this will determine if the interval should be by distance ([constant PATH_INTERVAL_DISTANCE]) or subdivision fractions ([constant PATH_INTERVAL_SUBDIVIDE]).
</member>
<member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined">
- If [code]true[/code] the start and end of our path are joined together ensuring there is no seam when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], if [code]true[/code] the ends of the path are joined, by adding an extrusion between the last and first points of the path.
</member>
<member name="path_local" type="bool" setter="set_path_local" getter="is_path_local">
- If [code]false[/code] we extrude centered on our path, if [code]true[/code] we extrude in relation to the position of our CSGPolygon3D when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], if [code]true[/code] the [Transform3D] of the [CSGPolygon3D] is used as the starting point for the extrusions, not the [Transform3D] of the [member path_node].
</member>
<member name="path_node" type="NodePath" setter="set_path_node" getter="get_path_node">
- The [Shape3D] object containing the path along which we extrude when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], the location of the [Path3D] object used to extrude the [member polygon].
</member>
<member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation">
- The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH].
+ When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded.
+ </member>
+ <member name="path_simplify_angle" type="float" setter="set_path_simplify_angle" getter="get_path_simplify_angle">
+ When [member mode] is [constant MODE_PATH], extrusions that are less than this angle, will be merged together to reduce polygon count.
+ </member>
+ <member name="path_u_distance" type="float" setter="set_path_u_distance" getter="get_path_u_distance">
+ 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 )">
- Point array that defines the shape that we'll extrude.
+ <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.
</member>
<member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false">
- Generates smooth normals so smooth shading is applied to our mesh.
+ If [code]true[/code], applies smooth shading to the extrusions.
</member>
<member name="spin_degrees" type="float" setter="set_spin_degrees" getter="get_spin_degrees">
- Degrees to rotate our extrusion for each slice when [member mode] is [constant MODE_SPIN].
+ When [member mode] is [constant MODE_SPIN], the total number of degrees the [member polygon] is rotated when extruding.
</member>
<member name="spin_sides" type="int" setter="set_spin_sides" getter="get_spin_sides">
- Number of extrusion when [member mode] is [constant MODE_SPIN].
+ When [member mode] is [constant MODE_SPIN], the number of extrusions made.
</member>
</members>
<constants>
<constant name="MODE_DEPTH" value="0" enum="Mode">
- Shape3D is extruded to [member depth].
+ The [member polygon] shape is extruded along the negative Z axis.
</constant>
<constant name="MODE_SPIN" value="1" enum="Mode">
- Shape3D is extruded by rotating it around an axis.
+ The [member polygon] shape is extruded by rotating it around the Y axis.
</constant>
<constant name="MODE_PATH" value="2" enum="Mode">
- Shape3D is extruded along a path set by a [Shape3D] set in [member path_node].
+ The [member polygon] shape is extruded along the [Path3D] specified in [member path_node].
</constant>
<constant name="PATH_ROTATION_POLYGON" value="0" enum="PathRotation">
- Slice is not rotated.
+ The [member polygon] shape is not rotated.
+ [b]Note:[/b] Requires the path Z coordinates to continually decrease to ensure viable shapes.
</constant>
<constant name="PATH_ROTATION_PATH" value="1" enum="PathRotation">
- Slice is rotated around the up vector of the path.
+ The [member polygon] shape is rotated along the path, but it is not rotated around the path axis.
+ [b]Note:[/b] Requires the path Z coordinates to continually decrease to ensure viable shapes.
</constant>
<constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation">
- Slice is rotate to match the path exactly.
+ The [member polygon] shape follows the path and its rotations around the path axis.
+ </constant>
+ <constant name="PATH_INTERVAL_DISTANCE" value="0" enum="PathIntervalType">
+ When [member mode] is set to [constant MODE_PATH], [member path_interval] will determine the distance, in meters, each interval of the path will extrude.
+ </constant>
+ <constant name="PATH_INTERVAL_SUBDIVIDE" value="1" enum="PathIntervalType">
+ When [member mode] is set to [constant MODE_PATH], [member path_interval] will subdivide the polygons along the path.
</constant>
</constants>
</class>
diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml
index 31b7360fac..8f4c8b9451 100644
--- a/modules/csg/doc_classes/CSGPrimitive3D.xml
+++ b/modules/csg/doc_classes/CSGPrimitive3D.xml
@@ -8,13 +8,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
Invert the faces of the mesh.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index dac556c7f1..f5031064d6 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -9,58 +9,46 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
+ <method name="get_collision_layer_value" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
+ <method name="get_collision_mask_value" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="layer_number" type="int" />
<description>
- Returns an individual bit on the collision mask.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_meshes" qualifiers="const">
- <return type="Array">
- </return>
+ <return type="Array" />
<description>
- Returns an [Array] with two elements, the first is the [Transform] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape.
+ Returns an [Array] with two elements, the first is the [Transform3D] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape.
</description>
</method>
<method name="is_root_shape" qualifiers="const">
- <return type="bool">
- </return>
+ <return type="bool" />
<description>
Returns [code]true[/code] if this is a root shape and is thus the object that is rendered.
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
+ <method name="set_collision_layer_value">
+ <return type="void" />
+ <argument index="0" name="layer_number" type="int" />
+ <argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the layer mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
+ <method name="set_collision_mask_value">
+ <return type="void" />
+ <argument index="0" name="layer_number" type="int" />
+ <argument index="1" name="value" type="bool" />
<description>
- Sets individual bits on the collision mask. Use this if you only need to change one layer's value.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
@@ -71,10 +59,10 @@
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this CSG shape scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ The physics layers this CSG shape scans for collisions. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
index 4d5b3be099..b8dfb4cf5f 100644
--- a/modules/csg/doc_classes/CSGSphere3D.xml
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the sphere.
@@ -27,6 +25,4 @@
If [code]true[/code] the normals of the sphere are set to give a smooth effect making the sphere seem rounded. If [code]false[/code] the sphere will have a flat shaded look.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGTorus3D.xml b/modules/csg/doc_classes/CSGTorus3D.xml
index abe3eab913..91ee63a4c9 100644
--- a/modules/csg/doc_classes/CSGTorus3D.xml
+++ b/modules/csg/doc_classes/CSGTorus3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0">
The inner radius of the torus.
@@ -30,6 +28,4 @@
If [code]true[/code] the normals of the torus are set to give a smooth effect making the torus seem rounded. If [code]false[/code] the torus will have a flat shaded look.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg
index 67e34df444..2740cc2f8c 100644
--- a/modules/csg/icons/CSGBox3D.svg
+++ b/modules/csg/icons/CSGBox3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-<path transform="translate(0 1036.4)" d="m8 0.94531-7 3.5v7.2227l7 3.5 0.29492-0.14844c-0.18282-0.30101-0.29492-0.64737-0.29492-1.0195v-2c0-0.72651 0.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c0.36419 0 0.70336 0.10754 1 0.2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc9c9c" stroke-width="1.0667"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/><path d="m8 .94531-7 3.5v7.2227l7 3.5.29492-.14844c-.18282-.30101-.29492-.64737-.29492-1.0195v-2c0-.72651.40824-1.3664 1-1.7168v-1.6699l4-2v1.3867h1c.36419 0 .70336.10754 1 .2832v-3.8379zm0 2.1152 3.9395 1.9707-3.9395 1.9688-3.9395-1.9688zm-5 3.5527 4 2v3.9414l-4-2.002z" fill="#fc7f7f" stroke-width="1.0667"/></svg>
diff --git a/modules/csg/icons/CSGCapsule3D.svg b/modules/csg/icons/CSGCapsule3D.svg
index 92a7b5a870..db4f71864b 100644
--- a/modules/csg/icons/CSGCapsule3D.svg
+++ b/modules/csg/icons/CSGCapsule3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922 0.092943 0 0.18367-0.008623 0.27539-0.013672-0.17055-0.29341-0.27539-0.62792-0.27539-0.98633v-2c0-0.72887 0.41095-1.3691 1.0059-1.7188v-0.28125c0.34771-0.034464 0.68259-0.10691 1.0156-0.19922 0.10394-0.99856 0.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-0.66556-0.1047-1.2974-0.37231-1.9941-0.66211v-1.3223c0-1.3474 0.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957 0.4088 1.9941 1.5256 1.9941 2.873v1.3457c-0.68406 0.3054-1.3142 0.57292-1.9941 0.66602v-4.8848zm-4.0059 6.334c0.67836 0.2231 1.3126 0.44599 1.9941 0.52539v2.8848c-1.1957-0.4092-1.9941-1.5237-1.9941-2.8711v-0.53906z" fill="#fc9c9c"/>
-<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-2.7527 0-5 2.2418-5 4.9902v4.0176c0 2.7484 2.2473 4.9922 5 4.9922.092943 0 .18367-.008623.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72887.41095-1.3691 1.0059-1.7188v-.28125c.34771-.034464.68259-.10691 1.0156-.19922.10394-.99856.95603-1.8008 1.9785-1.8008h1v-2.0098c0-2.7484-2.2473-4.9902-5-4.9902zm-1.0059 2.127v4.8574c-.66556-.1047-1.2974-.37231-1.9941-.66211v-1.3223c0-1.3474.79841-2.4642 1.9941-2.873zm2.0117 0c1.1957.4088 1.9941 1.5256 1.9941 2.873v1.3457c-.68406.3054-1.3142.57292-1.9941.66602v-4.8848zm-4.0059 6.334c.67836.2231 1.3126.44599 1.9941.52539v2.8848c-1.1957-.4092-1.9941-1.5237-1.9941-2.8711v-.53906z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGCombiner3D.svg b/modules/csg/icons/CSGCombiner3D.svg
index cce2902e24..692ba54cb8 100644
--- a/modules/csg/icons/CSGCombiner3D.svg
+++ b/modules/csg/icons/CSGCombiner3D.svg
@@ -1,8 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-<g fill="#fc9c9c">
-<path transform="translate(0 1036.4)" d="m3 1c-1.1046 0-2 0.89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-0.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046 0.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc9c9c"/>
-</g>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/><path d="m3 1c-1.1046 0-2 .89543-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.1046-.89543-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm0 4c0 1.1046.89543 2 2 2v-2zm4 0v2h2v-2z" fill="#fc7f7f"/></svg>
diff --git a/modules/csg/icons/CSGCylinder3D.svg b/modules/csg/icons/CSGCylinder3D.svg
index 645a74c79b..4bc2427887 100644
--- a/modules/csg/icons/CSGCylinder3D.svg
+++ b/modules/csg/icons/CSGCylinder3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 14.999999 14.999999" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path transform="scale(.9375)" d="m8 1c-1.7469 0-3.328 0.22648-4.5586 0.63672-0.61528 0.20512-1.1471 0.45187-1.5898 0.80078-0.44272 0.34891-0.85156 0.88101-0.85156 1.5625v8c0 0.68149 0.40884 1.2155 0.85156 1.5645 0.44272 0.34891 0.97457 0.59577 1.5898 0.80078 1.2306 0.41024 2.8117 0.63477 4.5586 0.63477 0.095648 0 0.18467-0.008426 0.2793-0.009766-0.1722-0.29446-0.2793-0.62995-0.2793-0.99023v-1c-1.5668 0-2.9867-0.2195-3.9277-0.5332-0.46329-0.15435-0.90474-0.33752-1.0723-0.4668v-5.8125c0.1468 0.058667 0.2835 0.12515 0.44141 0.17773 1.2306 0.41024 2.8117 0.63477 4.5586 0.63477s3.328-0.22453 4.5586-0.63477c0.15791-0.052267 0.29461-0.11864 0.44141-0.17773v1.8125h1c0.36396 0 0.70348 0.10774 1 0.2832v-4.2832c0-0.68149-0.40884-1.2136-0.85156-1.5625-0.44272-0.34891-0.97457-0.59566-1.5898-0.80078-1.2306-0.41024-2.8117-0.63672-4.5586-0.63672zm0 2c1.5668 0 2.9867 0.22145 3.9277 0.53516 0.46368 0.15456 0.80138 0.33741 0.96875 0.4668-0.16752 0.12928-0.50546 0.3105-0.96875 0.46484-0.94102 0.31371-2.361 0.5332-3.9277 0.5332s-2.9867-0.2195-3.9277-0.5332c-0.46329-0.15435-0.80123-0.33556-0.96875-0.46484 0.16737-0.12939 0.50507-0.31224 0.96875-0.4668 0.94102-0.31371 2.361-0.53516 3.9277-0.53516z" fill="#fc9c9c" stroke-width="1.0667"/>
-<path d="m11.25 8.4375c-0.51938 0-0.9375 0.41812-0.9375 0.9375v0.9375h1.875v1.875h0.9375c0.51938 0 0.9375-0.41812 0.9375-0.9375v-1.875c0-0.51938-0.41812-0.9375-0.9375-0.9375zm0.9375 3.75h-1.875v-1.875h-0.9375c-0.51938 0-0.9375 0.41812-0.9375 0.9375v1.875c0 0.51938 0.41812 0.9375 0.9375 0.9375h1.875c0.51938 0 0.9375-0.41812 0.9375-0.9375z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-1.7469 0-3.328.22648-4.5586.63672-.61528.20512-1.1471.45187-1.5898.80078-.44272.34891-.85156.88101-.85156 1.5625v8c0 .68149.40884 1.2155.85156 1.5645.44272.34891.97457.59577 1.5898.80078 1.2306.41024 2.8117.63477 4.5586.63477.095648 0 .18467-.008426.2793-.009766-.1722-.29446-.2793-.62995-.2793-.99023v-1c-1.5668 0-2.9867-.2195-3.9277-.5332-.46329-.15435-.90474-.33752-1.0723-.4668v-5.8125c.1468.058667.2835.12515.44141.17773 1.2306.41024 2.8117.63477 4.5586.63477s3.328-.22453 4.5586-.63477c.15791-.052267.29461-.11864.44141-.17773v1.8125h1c.36396 0 .70348.10774 1 .2832v-4.2832c0-.68149-.40884-1.2136-.85156-1.5625-.44272-.34891-.97457-.59566-1.5898-.80078-1.2306-.41024-2.8117-.63672-4.5586-.63672zm0 2c1.5668 0 2.9867.22145 3.9277.53516.46368.15456.80138.33741.96875.4668-.16752.12928-.50546.3105-.96875.46484-.94102.31371-2.361.5332-3.9277.5332s-2.9867-.2195-3.9277-.5332c-.46329-.15435-.80123-.33556-.96875-.46484.16737-.12939.50507-.31224.96875-.4668.94102-.31371 2.361-.53516 3.9277-.53516z" fill="#fc7f7f" stroke-width="1.0667" transform="scale(.9375)"/><path d="m11.25 8.4375c-.51938 0-.9375.41812-.9375.9375v.9375h1.875v1.875h.9375c.51938 0 .9375-.41812.9375-.9375v-1.875c0-.51938-.41812-.9375-.9375-.9375zm.9375 3.75h-1.875v-1.875h-.9375c-.51938 0-.9375.41812-.9375.9375v1.875c0 .51938.41812.9375.9375.9375h1.875c.51938 0 .9375-.41812.9375-.9375z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGMesh3D.svg b/modules/csg/icons/CSGMesh3D.svg
index 6e940a4aa5..8f4a1736fb 100644
--- a/modules/csg/icons/CSGMesh3D.svg
+++ b/modules/csg/icons/CSGMesh3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path d="m3 1c-1.1046 0-2 0.89543-2 2 5.649e-4 0.71397 0.38169 1.3735 1 1.7305v6.541c-0.61771 0.35663-0.99874 1.0152-1 1.7285 0 1.1046 0.89543 2 2 2 0.71397-5.65e-4 1.3735-0.38169 1.7305-1h3.2695v-2h-3.2715c-0.17478-0.30301-0.42598-0.55488-0.72852-0.73047v-5.8555l4.916 4.916c0.31428-0.20669 0.68609-0.33008 1.084-0.33008 0-0.3979 0.12338-0.76971 0.33008-1.084l-4.916-4.916h5.8574c0.17478 0.30301 0.42598 0.55488 0.72852 0.73047v3.2695h2v-3.2715c0.61771-0.35663 0.99874-1.0152 1-1.7285 0-1.1046-0.89543-2-2-2-0.71397 5.648e-4 -1.3735 0.38169-1.7305 1h-6.541c-0.35663-0.61771-1.0152-0.99874-1.7285-1z" fill="#fc9c9c"/>
-<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1c-1.1046 0-2 .89543-2 2 .0005649.71397.38169 1.3735 1 1.7305v6.541c-.61771.35663-.99874 1.0152-1 1.7285 0 1.1046.89543 2 2 2 .71397-.000565 1.3735-.38169 1.7305-1h3.2695v-2h-3.2715c-.17478-.30301-.42598-.55488-.72852-.73047v-5.8555l4.916 4.916c.31428-.20669.68609-.33008 1.084-.33008 0-.3979.12338-.76971.33008-1.084l-4.916-4.916h5.8574c.17478.30301.42598.55488.72852.73047v3.2695h2v-3.2715c.61771-.35663.99874-1.0152 1-1.7285 0-1.1046-.89543-2-2-2-.71397.0005648-1.3735.38169-1.7305 1h-6.541c-.35663-.61771-1.0152-.99874-1.7285-1z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGPolygon3D.svg b/modules/csg/icons/CSGPolygon3D.svg
index 71b03cb8e6..971f3577bb 100644
--- a/modules/csg/icons/CSGPolygon3D.svg
+++ b/modules/csg/icons/CSGPolygon3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m7.9629 1.002c-0.14254 0.00487-0.28238 0.04016-0.41016 0.10352l-6 3c-0.33878 0.16944-0.55276 0.51574-0.55273 0.89453v5.832c-0.105 0.61631 0.37487 1.1768 1 1.168h5v2c2.16e-5 0.67546 0.64487 1.1297 1.2617 0.95898-0.16118-0.28721-0.26172-0.61135-0.26172-0.95898v-2c0-0.72673 0.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c0.36397 0 0.70348 0.10774 1 0.2832v-3.2773c6e-6 -0.00195 6e-6 -0.0039094 0-0.0058594 2.6e-5 -0.37879-0.21395-0.72509-0.55273-0.89453l-6-3c-0.15022-0.074574-0.31679-0.11017-0.48438-0.10352zm0.037109 2.1172l3.7637 1.8809-2.7637 1.3809v-1.3809c-5.52e-5 -0.55226-0.44774-0.99994-1-1h-1.7617l1.7617-0.88086zm-5 2.8809h4v4h-4v-4z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#fc9c9c" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9629 1.002c-.14254.00487-.28238.04016-.41016.10352l-6 3c-.33878.16944-.55276.51574-.55273.89453v5.832c-.105.61631.37487 1.1768 1 1.168h5v2c.0000216.67546.64487 1.1297 1.2617.95898-.16118-.28721-.26172-.61135-.26172-.95898v-2c0-.72673.40794-1.3664 1-1.7168v-1.666l4-2v1.3828h1c.36397 0 .70348.10774 1 .2832v-3.2773c.000006-.00195.000006-.0039094 0-.0058594.000026-.37879-.21395-.72509-.55273-.89453l-6-3c-.15022-.074574-.31679-.11017-.48438-.10352zm.037109 2.1172 3.7637 1.8809-2.7637 1.3809v-1.3809c-.0000552-.55226-.44774-.99994-1-1h-1.7617l1.7617-.88086zm-5 2.8809h4v4h-4z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGSphere3D.svg b/modules/csg/icons/CSGSphere3D.svg
index f81b566993..770af80632 100644
--- a/modules/csg/icons/CSGSphere3D.svg
+++ b/modules/csg/icons/CSGSphere3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g>
-<path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 0.093042 0 0.18321-0.01004 0.27539-0.013672-0.17055-0.29341-0.27539-0.62792-0.27539-0.98633v-2c0-0.72673 0.40794-1.3664 1-1.7168v-0.33398c0.34074-0.019259 0.67728-0.069097 1.0156-0.10547 0.083091-1.0187 0.94713-1.8438 1.9844-1.8438h2c0.35841 0 0.69292 0.10484 0.98633 0.27539 0.003633-0.092184 0.013672-0.18235 0.013672-0.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-0.071342-2.6061-0.29819-3.9434-0.69141 0.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549 0.41253 3.637 2.0767 3.9414 4.1699-1.3046 0.36677-2.6158 0.60259-3.9414 0.6875v-4.8574zm-5.7793 6.2988c1.2733 0.31892 2.5337 0.50215 3.7793 0.5625v2.9414c-1.8291-0.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc9c9c"/>
-<path d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1c-3.8541 0-7 3.1459-7 7 0 3.8542 3.1459 7 7 7 .093042 0 .18321-.01004.27539-.013672-.17055-.29341-.27539-.62792-.27539-.98633v-2c0-.72673.40794-1.3664 1-1.7168v-.33398c.34074-.019259.67728-.069097 1.0156-.10547.083091-1.0187.94713-1.8438 1.9844-1.8438h2c.35841 0 .69292.10484.98633.27539.003633-.092184.013672-.18235.013672-.27539 0-3.8541-3.1459-7-7-7zm-1 2.0977v4.8711c-1.2931-.071342-2.6061-.29819-3.9434-.69141.30081-2.0978 1.8852-3.7665 3.9434-4.1797zm2 0c2.0549.41253 3.637 2.0767 3.9414 4.1699-1.3046.36677-2.6158.60259-3.9414.6875zm-5.7793 6.2988c1.2733.31892 2.5337.50215 3.7793.5625v2.9414c-1.8291-.36719-3.266-1.7339-3.7793-3.5039z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg
index 3d30aa47b2..ece9c68d28 100644
--- a/modules/csg/icons/CSGTorus3D.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
@@ -1,6 +1 @@
-<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
-<g transform="translate(0 -1036.4)">
-<path transform="translate(0 1036.4)" d="m8 3c-1.8145 0-3.4691 0.41721-4.7461 1.1621-1.277 0.745-2.2539 1.9082-2.2539 3.3379 0 1.4298 0.9769 2.5949 2.2539 3.3398 1.277 0.7449 2.9316 1.1602 4.7461 1.1602 0-1.0907 0.90931-2 2-2 0-0.080836 0.013744-0.15778 0.023438-0.23633-0.61769 0.14673-1.3008 0.23633-2.0234 0.23633-1.4992 0-2.8437-0.36687-3.7383-0.88867-0.89456-0.5219-1.2617-1.108-1.2617-1.6113 0-0.5032 0.36716-1.0876 1.2617-1.6094 0.89456-0.5219 2.2391-0.89062 3.7383-0.89062s2.8437 0.36872 3.7383 0.89062c0.89456 0.5218 1.2617 1.1062 1.2617 1.6094 0 0.15978-0.053679 0.32822-0.13281 0.5h1.1328c0.32481 0 0.62893 0.088408 0.90234 0.23047 0.057552-0.23582 0.097656-0.47718 0.097656-0.73047 0-1.4297-0.9769-2.5929-2.2539-3.3379-1.277-0.7449-2.9316-1.1621-4.7461-1.1621z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#fc9c9c" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/>
-<path transform="translate(0 1036.4)" d="m12 9c-0.55401 0-1 0.44599-1 1v1h2v2h1c0.55401 0 1-0.44599 1-1v-2c0-0.55401-0.44599-1-1-1h-2zm1 4h-2v-2h-1c-0.55401 0-1 0.44599-1 1v2c0 0.55401 0.44599 1 1 1h2c0.55401 0 1-0.44599 1-1v-1z" fill="#84c2ff"/>
-</g>
-</svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3c-1.8145 0-3.4691.41721-4.7461 1.1621-1.277.745-2.2539 1.9082-2.2539 3.3379 0 1.4298.9769 2.5949 2.2539 3.3398s2.9316 1.1602 4.7461 1.1602c0-1.0907.90931-2 2-2 0-.080836.013744-.15778.023438-.23633-.61769.14673-1.3008.23633-2.0234.23633-1.4992 0-2.8437-.36687-3.7383-.88867-.89456-.5219-1.2617-1.108-1.2617-1.6113 0-.5032.36716-1.0876 1.2617-1.6094.89456-.5219 2.2391-.89062 3.7383-.89062s2.8437.36872 3.7383.89062c.89456.5218 1.2617 1.1062 1.2617 1.6094 0 .15978-.053679.32822-.13281.5h1.1328c.32481 0 .62893.088408.90234.23047.057552-.23582.097656-.47718.097656-.73047 0-1.4297-.9769-2.5929-2.2539-3.3379-1.277-.7449-2.9316-1.1621-4.7461-1.1621z" fill="#fc7f7f"/><path d="m12 9c-.55401 0-1 .44599-1 1v1h2v2h1c.55401 0 1-.44599 1-1v-2c0-.55401-.44599-1-1-1zm1 4h-2v-2h-1c-.55401 0-1 .44599-1 1v2c0 .55401.44599 1 1 1h2c.55401 0 1-.44599 1-1z" fill="#5fb2ff"/></svg>
diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp
index a8bcc2fed1..a47390c2b2 100644
--- a/modules/csg/register_types.cpp
+++ b/modules/csg/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,15 +36,15 @@
void register_csg_types() {
#ifndef _3D_DISABLED
- ClassDB::register_virtual_class<CSGShape3D>();
- ClassDB::register_virtual_class<CSGPrimitive3D>();
- ClassDB::register_class<CSGMesh3D>();
- ClassDB::register_class<CSGSphere3D>();
- ClassDB::register_class<CSGBox3D>();
- ClassDB::register_class<CSGCylinder3D>();
- ClassDB::register_class<CSGTorus3D>();
- ClassDB::register_class<CSGPolygon3D>();
- ClassDB::register_class<CSGCombiner3D>();
+ 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);
#ifdef TOOLS_ENABLED
EditorPlugins::add_by_type<EditorPluginCSG>();
diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h
index 926e598561..8747b3fade 100644
--- a/modules/csg/register_types.h
+++ b/modules/csg/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */