diff options
Diffstat (limited to 'modules/csg')
-rw-r--r-- | modules/csg/config.py | 2 | ||||
-rw-r--r-- | modules/csg/csg.cpp | 28 | ||||
-rw-r--r-- | modules/csg/csg.h | 10 | ||||
-rw-r--r-- | modules/csg/csg_gizmos.cpp | 90 | ||||
-rw-r--r-- | modules/csg/csg_gizmos.h | 22 | ||||
-rw-r--r-- | modules/csg/csg_shape.cpp | 872 | ||||
-rw-r--r-- | modules/csg/csg_shape.h | 19 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGBox3D.xml | 2 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGMesh3D.xml | 3 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGPolygon3D.xml | 44 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGShape3D.xml | 54 | ||||
-rw-r--r-- | modules/csg/icons/CSGBox3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGCapsule3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGCombiner3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGCylinder3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGMesh3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGPolygon3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGSphere3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGTorus3D.svg | 2 | ||||
-rw-r--r-- | modules/csg/register_types.cpp | 18 |
20 files changed, 508 insertions, 672 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 f0a2f17ba9..cb82b65307 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -42,7 +42,7 @@ inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2, 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) { + if (p_segement_points[0].is_equal_approx(p_segement_points[1])) { return p_uvs[0]; } @@ -53,13 +53,13 @@ inline static Vector2 interpolate_segment_uv(const Vector2 p_segement_points[2], } 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]; } @@ -265,7 +265,7 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< _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; @@ -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,7 +589,7 @@ 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) { @@ -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]); } @@ -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], @@ -1076,7 +1076,7 @@ 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) { _add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx); @@ -1137,7 +1137,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { } } - // 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] = { @@ -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 3fbed66e5c..c872860486 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -33,10 +33,10 @@ #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/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/list.h" #include "core/templates/map.h" #include "core/templates/oa_hash_map.h" @@ -60,7 +60,7 @@ 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 { @@ -165,8 +165,8 @@ struct CSGBrushOperation { Vector<Vertex2D> vertices; Vector<Face2D> faces; Plane plane; - Transform to_2D; - Transform to_3D; + Transform3D to_2D; + Transform3D to_3D; float vertex_snap2 = 0.0; inline int _get_point_idx(const Vector2 &p_point); diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index e23442ef99..2f8b354bb7 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -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)) { @@ -60,17 +62,17 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, } 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)) { @@ -85,23 +87,23 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int 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); @@ -129,10 +131,16 @@ 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::snapped(d, Node3DEditor::get_singleton()->get_translate_snap()); } @@ -142,7 +150,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca } Vector3 h = s->get_size(); - h[p_idx] = d * 2; + h[p_id] = d * 2; s->set_size(h); } @@ -150,7 +158,7 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca 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); @@ -162,9 +170,9 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca 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); } } @@ -185,15 +193,15 @@ void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Ca 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)) { @@ -227,7 +235,7 @@ void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, 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); @@ -236,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); @@ -252,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); @@ -261,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); @@ -292,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); { @@ -328,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); @@ -352,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)) { diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 8f7da35de3..2a6ab91102 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -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_gizmo_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 40ba457e43..bf11cc7f68 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -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,7 +44,7 @@ void CSGShape3D::set_use_collision(bool p_enable) { } if (use_collision) { - root_collision_shape.instance(); + 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()); @@ -88,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 { @@ -136,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; @@ -407,7 +415,7 @@ void CSGShape3D::_update_shape() { } } - root_mesh.instance(); + root_mesh.instantiate(); //create surfaces for (int i = 0; i < surfaces.size(); i++) { @@ -494,7 +502,7 @@ void CSGShape3D::_notification(int p_what) { } if (use_collision && is_root_shape()) { - root_collision_shape.instance(); + 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()); @@ -544,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 { @@ -574,7 +582,7 @@ 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; } @@ -601,11 +609,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); @@ -774,7 +782,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]; @@ -816,7 +824,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]; @@ -841,7 +849,7 @@ CSGBrush *CSGMesh3D::_build_brush() { void CSGMesh3D::_mesh_changed() { _make_dirty(); - update_gizmo(); + update_gizmos(); } void CSGMesh3D::set_material(const Ref<Material> &p_material) { @@ -864,7 +872,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) { @@ -880,7 +888,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() { @@ -919,49 +927,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; - const double lat_step = Math_TAU / rings; - const double lon_step = Math_TAU / radial_segments; - - for (int i = 1; i <= rings; i++) { - double lat0 = lat_step * (i - 1) - Math_TAU / 4; - double z0 = Math::sin(lat0); - double zr0 = Math::cos(lat0); - double u0 = double(i - 1) / rings; - - double lat1 = lat_step * i - Math_TAU / 4; - 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 = lon_step * (j - 1); - double x0 = Math::cos(lng0); - double y0 = Math::sin(lng0); - double v0 = double(i - 1) / radial_segments; - - double lng1 = lon_step * j; - 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]; @@ -977,8 +987,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]; @@ -1025,14 +1035,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(); + update_gizmos(); } float CSGSphere3D::get_radius() const { @@ -1042,7 +1052,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 { @@ -1052,7 +1062,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 { @@ -1160,7 +1170,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; @@ -1195,13 +1205,13 @@ void CSGBox3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); - 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 CSGBox3D::set_size(const Vector3 &p_size) { size = p_size; _make_dirty(); - update_gizmo(); + update_gizmos(); } Vector3 CSGBox3D::get_size() const { @@ -1211,7 +1221,7 @@ Vector3 CSGBox3D::get_size() const { void CSGBox3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); - update_gizmo(); + update_gizmos(); } Ref<Material> CSGBox3D::get_material() const { @@ -1371,18 +1381,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(); + update_gizmos(); } float CSGCylinder3D::get_radius() const { @@ -1392,7 +1402,7 @@ float CSGCylinder3D::get_radius() const { void CSGCylinder3D::set_height(const float p_height) { height = p_height; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGCylinder3D::get_height() const { @@ -1403,7 +1413,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 { @@ -1413,7 +1423,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 { @@ -1590,18 +1600,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(); + update_gizmos(); } float CSGTorus3D::get_inner_radius() const { @@ -1611,7 +1621,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(); + update_gizmos(); } float CSGTorus3D::get_outer_radius() const { @@ -1622,7 +1632,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 { @@ -1633,7 +1643,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 { @@ -1670,110 +1680,80 @@ CSGTorus3D::CSGTorus3D() { /////////////// CSGBrush *CSGPolygon3D::_build_brush() { - // set our bounding box + CSGBrush *brush = memnew(CSGBrush); if (polygon.size() < 3) { - return memnew(CSGBrush); + 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 memnew(CSGBrush); + 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 memnew(CSGBrush); - } - Node *n = get_node(path_node); - if (!n) { - return memnew(CSGBrush); - } - path = Object::cast_to<Path3D>(n); if (!path) { - return memnew(CSGBrush); + 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 memnew(CSGBrush); - } - if (curve->get_baked_length() <= 0) { - return memnew(CSGBrush); + 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; 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; - } 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; @@ -1784,362 +1764,216 @@ 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); - AABB aabb; //must be computed - { - Vector3 *facesw = faces.ptrw(); - Vector2 *uvsw = uvs.ptrw(); - bool *smoothw = smooth.ptrw(); - Ref<Material> *materialsw = materials.ptrw(); - bool *invertw = invert.ptrw(); - - int face = 0; - - 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) - }; + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); + + int face = 0; + Transform3D base_xform; + Transform3D current_xform; + Transform3D previous_xform; + double u_step = 1.0 / extrusions; + 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->get_baked_length(); + } - // face 1 - facesw[face * 3 + 0] = v[0]; - facesw[face * 3 + 1] = v[1]; - facesw[face * 3 + 2] = v[2]; + if (mode == MODE_PATH) { + if (!path_local) { + base_xform = path->get_global_transform(); + } - uvsw[face * 3 + 0] = u[0]; - uvsw[face * 3 + 1] = u[1]; - uvsw[face * 3 + 2] = u[2]; + 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; - smoothw[face] = smooth_faces; - invertw[face] = invert_val; - materialsw[face] = material; + if (path_joined) { + Vector3 last_point = curve->interpolate_baked(curve->get_baked_length()); + direction = next_point - last_point; + } - face++; + 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; + } - // face 2 - facesw[face * 3 + 0] = v[2]; - facesw[face * 3 + 1] = v[3]; - facesw[face * 3 + 2] = v[0]; + Transform3D facing = Transform3D().looking_at(direction, current_up); + current_xform = base_xform.translated(current_point) * facing; + } - uvsw[face * 3 + 0] = u[2]; - uvsw[face * 3 + 1] = u[3]; - uvsw[face * 3 + 2] = u[0]; + // 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; + } - smoothw[face] = smooth_faces; - invertw[face] = invert_val; - materialsw[face] = material; + smoothw[face] = false; + materialsw[face] = material; + invertw[face] = invert_faces; + face++; + } + } - face++; - } + // Add extrusion faces. + for (int x0 = 0; x0 < extrusions; x0++) { + previous_xform = current_xform; + switch (mode) { + case MODE_DEPTH: { + current_xform.translate(Vector3(0, 0, -depth)); } 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 = -Math::deg2rad(inci * spin_degrees); - float angi_n = -Math::deg2rad(inci_n * spin_degrees); - - 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++; - } - } - - 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++; - } - } - } + current_xform.rotate(Vector3(0, 1, 0), spin_step); } 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(); - + 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 { - local_dir = lookat_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 - - xf = path_to_this * xf; - - if (i > 0) { - if (path_continuous_u) { - u1 = u2; - u2 += (prev_xf.origin - xf.origin).length(); - }; - - //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(); - - 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)), - }; - - Vector2 u[4] = { - Vector2(u1, 1), - Vector2(u1, 0), - Vector2(u2, 0), - Vector2(u2, 1) - }; - - // 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; - - face++; - - // 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]; - - smoothw[face] = smooth_faces; - invertw[face] = invert_val; - materialsw[face] = material; - - 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++; - } + next_offset = current_offset; } + } - 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++; - } - } + 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; - prev_xf = xf; + 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; } + Transform3D facing = Transform3D().looking_at(direction, current_up); + current_xform = base_xform.translated(current_point) * facing; } break; } - if (face != face_count) { - ERR_PRINT("Face mismatch bug! fix code"); + double u0 = x0 * u_step; + double u1 = ((x0 + 1) * u_step); + if (mode == MODE_PATH && !path_continuous_u) { + u0 = 0.0; + u1 = 1.0; } - for (int i = 0; i < face_count * 3; i++) { - if (i == 0) { - aabb.position = facesw[i]; - } else { - aabb.expand_to(facesw[i]); + + 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] = { + 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(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]; + + 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_faces; + materialsw[face] = material; + + face++; + + // 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]; + + smoothw[face] = smooth_faces; + invertw[face] = invert_faces; + materialsw[face] = material; + + 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; + + // 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); + + facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0)); + uvsw[face * 3 + face_vertex_idx] = uv; } - // invert UVs on the Y-axis OpenGL = upside down - uvsw[i].y = 1.0 - uvsw[i].y; + smoothw[face] = false; + materialsw[face] = material; + invertw[face] = invert_faces; + face++; } } + ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly."); + brush->build_from_faces(faces, uvs, smooth, materials, invert); return brush; @@ -2147,23 +1981,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); @@ -2171,11 +2005,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() { @@ -2197,10 +2031,10 @@ 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", "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_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); @@ -2223,17 +2057,17 @@ 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::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.1,1.0,0.05,exp"), "set_path_interval", "get_path_interval"); 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::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); @@ -2247,7 +2081,7 @@ void CSGPolygon3D::_bind_methods() { void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) { polygon = p_polygon; _make_dirty(); - update_gizmo(); + update_gizmos(); } Vector<Vector2> CSGPolygon3D::get_polygon() const { @@ -2257,7 +2091,7 @@ Vector<Vector2> CSGPolygon3D::get_polygon() const { void CSGPolygon3D::set_mode(Mode p_mode) { mode = p_mode; _make_dirty(); - update_gizmo(); + update_gizmos(); notify_property_list_changed(); } @@ -2269,7 +2103,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 { @@ -2289,18 +2123,18 @@ 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 { @@ -2310,7 +2144,7 @@ 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 { @@ -2318,10 +2152,10 @@ NodePath CSGPolygon3D::get_path_node() const { } void CSGPolygon3D::set_path_interval(float p_interval) { - ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001."); + ERR_FAIL_COND_MSG(p_interval <= 0 || p_interval > 1, "Path interval must be greater than 0 and less than or equal to 1.0."); path_interval = p_interval; _make_dirty(); - update_gizmo(); + update_gizmos(); } float CSGPolygon3D::get_path_interval() const { @@ -2331,7 +2165,7 @@ float CSGPolygon3D::get_path_interval() const { 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 { @@ -2341,7 +2175,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 { @@ -2351,7 +2185,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 { @@ -2395,10 +2229,10 @@ CSGPolygon3D::CSGPolygon3D() { spin_degrees = 360; spin_sides = 8; smooth_faces = false; - path_interval = 1; - path_rotation = PATH_ROTATION_PATH; + path_interval = 1.0; + path_rotation = PATH_ROTATION_PATH_FOLLOW; path_local = false; - path_continuous_u = false; + path_continuous_u = true; path_joined = false; - path_cache = nullptr; + path = nullptr; } diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index de7de09f00..5cf371665e 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -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" @@ -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 = 0; Vector3 *verticesw = nullptr; Vector3 *normalsw = nullptr; Vector2 *uvsw = nullptr; - float *tansw = 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(); @@ -361,7 +360,7 @@ private: PathRotation path_rotation; bool path_local; - Node *path_cache; + Path3D *path; bool smooth_faces; bool path_continuous_u; diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml index b1d0454b76..5bb1c4e75b 100644 --- a/modules/csg/doc_classes/CSGBox3D.xml +++ b/modules/csg/doc_classes/CSGBox3D.xml @@ -14,7 +14,7 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the box. </member> - <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> + <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)"> The box's width, height and depth. </member> </members> diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml index 1bab8f4ee9..5fa8427843 100644 --- a/modules/csg/doc_classes/CSGMesh3D.xml +++ b/modules/csg/doc_classes/CSGMesh3D.xml @@ -4,7 +4,7 @@ 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> @@ -16,6 +16,7 @@ </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> diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index c55fa0983e..5309cde956 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -4,7 +4,7 @@ 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> @@ -12,63 +12,65 @@ </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_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="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> </constants> </class> diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index dac556c7f1..446269f3f0 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> diff --git a/modules/csg/icons/CSGBox3D.svg b/modules/csg/icons/CSGBox3D.svg index ceef9196a7..2740cc2f8c 100644 --- a/modules/csg/icons/CSGBox3D.svg +++ b/modules/csg/icons/CSGBox3D.svg @@ -1 +1 @@ -<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="#84c2ff"/><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="#fc9c9c" stroke-width="1.0667"/></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 14e582ee84..db4f71864b 100644 --- a/modules/csg/icons/CSGCapsule3D.svg +++ b/modules/csg/icons/CSGCapsule3D.svg @@ -1 +1 @@ -<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="#fc9c9c"/><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="#84c2ff"/></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 50ce4179d9..692ba54cb8 100644 --- a/modules/csg/icons/CSGCombiner3D.svg +++ b/modules/csg/icons/CSGCombiner3D.svg @@ -1 +1 @@ -<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="#84c2ff"/><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="#fc9c9c"/></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 c84594928a..4bc2427887 100644 --- a/modules/csg/icons/CSGCylinder3D.svg +++ b/modules/csg/icons/CSGCylinder3D.svg @@ -1 +1 @@ -<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="#fc9c9c" 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="#84c2ff"/></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 962e71f6ae..8f4a1736fb 100644 --- a/modules/csg/icons/CSGMesh3D.svg +++ b/modules/csg/icons/CSGMesh3D.svg @@ -1 +1 @@ -<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="#fc9c9c"/><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="#84c2ff"/></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 1d496e5fd9..971f3577bb 100644 --- a/modules/csg/icons/CSGPolygon3D.svg +++ b/modules/csg/icons/CSGPolygon3D.svg @@ -1 +1 @@ -<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="#fc9c9c"/><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="#84c2ff"/></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 639e38f49f..770af80632 100644 --- a/modules/csg/icons/CSGSphere3D.svg +++ b/modules/csg/icons/CSGSphere3D.svg @@ -1 +1 @@ -<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="#fc9c9c"/><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="#84c2ff"/></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 eb8c0f37cb..ece9c68d28 100644 --- a/modules/csg/icons/CSGTorus3D.svg +++ b/modules/csg/icons/CSGTorus3D.svg @@ -1 +1 @@ -<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="#fc9c9c"/><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="#84c2ff"/></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 e28f44d1eb..a47390c2b2 100644 --- a/modules/csg/register_types.cpp +++ b/modules/csg/register_types.cpp @@ -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>(); |