diff options
Diffstat (limited to 'modules/csg')
-rw-r--r-- | modules/csg/SCsub | 4 | ||||
-rw-r--r-- | modules/csg/config.py | 21 | ||||
-rw-r--r-- | modules/csg/csg.cpp | 2156 | ||||
-rw-r--r-- | modules/csg/csg.h | 168 | ||||
-rw-r--r-- | modules/csg/csg_gizmos.cpp | 247 | ||||
-rw-r--r-- | modules/csg/csg_gizmos.h | 25 | ||||
-rw-r--r-- | modules/csg/csg_shape.cpp | 1064 | ||||
-rw-r--r-- | modules/csg/csg_shape.h | 101 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGBox3D.xml (renamed from modules/csg/doc_classes/CSGBox.xml) | 2 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGCombiner.xml | 15 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGCombiner3D.xml | 15 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGCylinder3D.xml (renamed from modules/csg/doc_classes/CSGCylinder.xml) | 2 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGMesh3D.xml (renamed from modules/csg/doc_classes/CSGMesh.xml) | 5 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGPolygon3D.xml (renamed from modules/csg/doc_classes/CSGPolygon.xml) | 18 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGPrimitive3D.xml (renamed from modules/csg/doc_classes/CSGPrimitive.xml) | 3 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGShape3D.xml (renamed from modules/csg/doc_classes/CSGShape.xml) | 6 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGSphere3D.xml (renamed from modules/csg/doc_classes/CSGSphere.xml) | 2 | ||||
-rw-r--r-- | modules/csg/doc_classes/CSGTorus3D.xml (renamed from modules/csg/doc_classes/CSGTorus.xml) | 2 | ||||
-rw-r--r-- | modules/csg/icons/CSGBox3D.svg (renamed from modules/csg/icons/icon_c_s_g_box.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGCapsule3D.svg (renamed from modules/csg/icons/icon_c_s_g_capsule.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGCombiner3D.svg (renamed from modules/csg/icons/icon_c_s_g_combiner.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGCylinder3D.svg (renamed from modules/csg/icons/icon_c_s_g_cylinder.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGMesh3D.svg (renamed from modules/csg/icons/icon_c_s_g_mesh.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGPolygon3D.svg (renamed from modules/csg/icons/icon_c_s_g_polygon.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGSphere3D.svg (renamed from modules/csg/icons/icon_c_s_g_sphere.svg) | 0 | ||||
-rw-r--r-- | modules/csg/icons/CSGTorus3D.svg (renamed from modules/csg/icons/icon_c_s_g_torus.svg) | 0 | ||||
-rw-r--r-- | modules/csg/register_types.cpp | 23 | ||||
-rw-r--r-- | modules/csg/register_types.h | 9 |
28 files changed, 1884 insertions, 2004 deletions
diff --git a/modules/csg/SCsub b/modules/csg/SCsub index 57c504efd8..641a42c187 100644 --- a/modules/csg/SCsub +++ b/modules/csg/SCsub @@ -1,7 +1,7 @@ #!/usr/bin/env python -Import('env') -Import('env_modules') +Import("env") +Import("env_modules") env_csg = env_modules.Clone() diff --git a/modules/csg/config.py b/modules/csg/config.py index 38ccc66d91..9106cbceca 100644 --- a/modules/csg/config.py +++ b/modules/csg/config.py @@ -1,21 +1,24 @@ def can_build(env, platform): return True + def configure(env): pass + def get_doc_classes(): return [ - "CSGBox", - "CSGCombiner", - "CSGCylinder", - "CSGMesh", - "CSGPolygon", - "CSGPrimitive", - "CSGShape", - "CSGSphere", - "CSGTorus", + "CSGBox3D", + "CSGCombiner3D", + "CSGCylinder3D", + "CSGMesh3D", + "CSGPolygon3D", + "CSGPrimitive3D", + "CSGShape3D", + "CSGSphere3D", + "CSGTorus3D", ] + def get_doc_path(): return "doc_classes" diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 925fff0cc8..df798623f9 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,33 +29,179 @@ /*************************************************************************/ #include "csg.h" -#include "core/math/face3.h" + #include "core/math/geometry.h" -#include "core/os/os.h" +#include "core/math/math_funcs.h" #include "core/sort_array.h" -#include "thirdparty/misc/triangulator.h" -void CSGBrush::clear() { - faces.clear(); +// Static helper functions. + +inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2, real_t p_distance) { + return (p_point1 - p_point2).length_squared() < p_distance * p_distance; +} + +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) { + return p_uvs[0]; + } + + float distance = (p_interpolation_point - p_segement_points[0]).length(); + float fraction = distance / segment_length; + + return p_uvs[0].lerp(p_uvs[1], fraction); +} + +inline static Vector2 interpolate_triangle_uv(const Vector2 p_vertices[3], const Vector2 p_uvs[3], const Vector2 &p_interpolation_point) { + if (p_interpolation_point.distance_squared_to(p_vertices[0]) < CMP_EPSILON2) { + return p_uvs[0]; + } + if (p_interpolation_point.distance_squared_to(p_vertices[1]) < CMP_EPSILON2) { + return p_uvs[1]; + } + if (p_interpolation_point.distance_squared_to(p_vertices[2]) < CMP_EPSILON2) { + return p_uvs[2]; + } + + Vector2 edge1 = p_vertices[1] - p_vertices[0]; + Vector2 edge2 = p_vertices[2] - p_vertices[0]; + Vector2 interpolation = p_interpolation_point - p_vertices[0]; + + float edge1_on_edge1 = edge1.dot(edge1); + float edge1_on_edge2 = edge1.dot(edge2); + float edge2_on_edge2 = edge2.dot(edge2); + float inter_on_edge1 = interpolation.dot(edge1); + float inter_on_edge2 = interpolation.dot(edge2); + float scale = (edge1_on_edge1 * edge2_on_edge2 - edge1_on_edge2 * edge1_on_edge2); + if (scale == 0) { + return p_uvs[0]; + } + + float v = (edge2_on_edge2 * inter_on_edge1 - edge1_on_edge2 * inter_on_edge2) / scale; + float w = (edge1_on_edge1 * inter_on_edge2 - edge1_on_edge2 * inter_on_edge1) / scale; + float u = 1.0f - v - w; + + return p_uvs[0] * u + p_uvs[1] * v + p_uvs[2] * w; +} + +static inline bool ray_intersects_triangle(const Vector3 &p_from, const Vector3 &p_dir, const Vector3 p_vertices[3], float p_tolerance, Vector3 &r_intersection_point) { + Vector3 edge1 = p_vertices[1] - p_vertices[0]; + Vector3 edge2 = p_vertices[2] - p_vertices[0]; + Vector3 h = p_dir.cross(edge2); + real_t a = edge1.dot(h); + // Check if ray is parallel to triangle. + if (Math::is_zero_approx(a)) { + return false; + } + real_t f = 1.0 / a; + + Vector3 s = p_from - p_vertices[0]; + real_t u = f * s.dot(h); + if (u < 0.0 - p_tolerance || u > 1.0 + p_tolerance) { + return false; + } + + Vector3 q = s.cross(edge1); + real_t v = f * p_dir.dot(q); + if (v < 0.0 - p_tolerance || u + v > 1.0 + p_tolerance) { + return false; + } + + // Ray intersects triangle. + // Calculate distance. + real_t t = f * edge2.dot(q); + // Confirm triangle is in front of ray. + if (t >= p_tolerance) { + r_intersection_point = p_from + p_dir * t; + return true; + } else { + return false; + } +} + +inline bool is_point_in_triangle(const Vector3 &p_point, const Vector3 p_vertices[3], int p_shifted = 0) { + real_t det = p_vertices[0].dot(p_vertices[1].cross(p_vertices[2])); + + // If determinant is, zero try shift the triangle and the point. + if (Math::is_zero_approx(det)) { + if (p_shifted > 2) { + // Triangle appears degenerate, so ignore it. + return false; + } + Vector3 shift_by; + shift_by[p_shifted] = 1; + Vector3 shifted_point = p_point + shift_by; + Vector3 shifted_vertices[3] = { p_vertices[0] + shift_by, p_vertices[1] + shift_by, p_vertices[2] + shift_by }; + return is_point_in_triangle(shifted_point, shifted_vertices, p_shifted + 1); + } + + // Find the barycentric coordinates of the point with respect to the vertices. + real_t lambda[3]; + lambda[0] = p_vertices[1].cross(p_vertices[2]).dot(p_point) / det; + lambda[1] = p_vertices[2].cross(p_vertices[0]).dot(p_point) / det; + lambda[2] = p_vertices[0].cross(p_vertices[1]).dot(p_point) / det; + + // Point is in the plane if all lambdas sum to 1. + if (!Math::is_equal_approx(lambda[0] + lambda[1] + lambda[2], 1)) { + return false; + } + + // Point is inside the triangle if all lambdas are positive. + if (lambda[0] < 0 || lambda[1] < 0 || lambda[2] < 0) { + return false; + } + + return true; } -void CSGBrush::build_from_faces(const PoolVector<Vector3> &p_vertices, const PoolVector<Vector2> &p_uvs, const PoolVector<bool> &p_smooth, const PoolVector<Ref<Material> > &p_materials, const PoolVector<bool> &p_invert_faces) { +inline static bool are_segements_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) { + Vector2 segment1 = p_segment1_points[1] - p_segment1_points[0]; + Vector2 segment2 = p_segment2_points[1] - p_segment2_points[0]; + real_t segment1_length2 = segment1.dot(segment1); + real_t segment2_length2 = segment2.dot(segment2); + real_t segment_onto_segment = segment2.dot(segment1); - clear(); + if (segment1_length2 < p_vertex_snap2 || segment2_length2 < p_vertex_snap2) { + return true; + } + + real_t max_separation2; + if (segment1_length2 > segment2_length2) { + max_separation2 = segment2_length2 - segment_onto_segment * segment_onto_segment / segment1_length2; + } else { + max_separation2 = segment1_length2 - segment_onto_segment * segment_onto_segment / segment2_length2; + } + + return max_separation2 < p_vertex_snap2; +} + +// CSGBrush + +void CSGBrush::_regen_face_aabbs() { + for (int i = 0; i < faces.size(); i++) { + faces.write[i].aabb = AABB(); + faces.write[i].aabb.position = faces[i].vertices[0]; + faces.write[i].aabb.expand_to(faces[i].vertices[1]); + faces.write[i].aabb.expand_to(faces[i].vertices[2]); + } +} + +void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces) { + faces.clear(); int vc = p_vertices.size(); ERR_FAIL_COND((vc % 3) != 0); - PoolVector<Vector3>::Read rv = p_vertices.read(); + const Vector3 *rv = p_vertices.ptr(); int uvc = p_uvs.size(); - PoolVector<Vector2>::Read ruv = p_uvs.read(); + const Vector2 *ruv = p_uvs.ptr(); int sc = p_smooth.size(); - PoolVector<bool>::Read rs = p_smooth.read(); + const bool *rs = p_smooth.ptr(); int mc = p_materials.size(); - PoolVector<Ref<Material> >::Read rm = p_materials.read(); + const Ref<Material> *rm = p_materials.ptr(); int ic = p_invert_faces.size(); - PoolVector<bool>::Read ri = p_invert_faces.read(); + const bool *ri = p_invert_faces.ptr(); Map<Ref<Material>, int> material_map; @@ -66,11 +212,13 @@ void CSGBrush::build_from_faces(const PoolVector<Vector3> &p_vertices, const Poo f.vertices[0] = rv[i * 3 + 0]; f.vertices[1] = rv[i * 3 + 1]; f.vertices[2] = rv[i * 3 + 2]; + if (uvc == vc) { f.uvs[0] = ruv[i * 3 + 0]; f.uvs[1] = ruv[i * 3 + 1]; f.uvs[2] = ruv[i * 3 + 2]; } + if (sc == vc / 3) { f.smooth = rs[i]; } else { @@ -87,12 +235,14 @@ void CSGBrush::build_from_faces(const PoolVector<Vector3> &p_vertices, const Poo Ref<Material> mat = rm[i]; if (mat.is_valid()) { const Map<Ref<Material>, int>::Element *E = material_map.find(mat); + if (E) { f.material = E->get(); } else { f.material = material_map.size(); material_map[mat] = f.material; } + } else { f.material = -1; } @@ -107,19 +257,7 @@ void CSGBrush::build_from_faces(const PoolVector<Vector3> &p_vertices, const Poo _regen_face_aabbs(); } -void CSGBrush::_regen_face_aabbs() { - - for (int i = 0; i < faces.size(); i++) { - - faces.write[i].aabb.position = faces[i].vertices[0]; - faces.write[i].aabb.expand_to(faces[i].vertices[1]); - faces.write[i].aabb.expand_to(faces[i].vertices[2]); - faces.write[i].aabb.grow_by(faces[i].aabb.get_longest_axis_size() * 0.001); //make it a tad bigger to avoid num precision errors - } -} - void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) { - faces = p_brush.faces; materials = p_brush.materials; @@ -132,937 +270,244 @@ void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) { _regen_face_aabbs(); } -//////////////////////// - -void CSGBrushOperation::BuildPoly::create(const CSGBrush *p_brush, int p_face, MeshMerge &mesh_merge, bool p_for_B) { - - //creates the initial face that will be used for clipping against the other faces - - Vector3 va[3] = { - p_brush->faces[p_face].vertices[0], - p_brush->faces[p_face].vertices[1], - p_brush->faces[p_face].vertices[2], - }; - - plane = Plane(va[0], va[1], va[2]); - - to_world.origin = va[0]; - - to_world.basis.set_axis(2, plane.normal); - to_world.basis.set_axis(0, (va[1] - va[2]).normalized()); - to_world.basis.set_axis(1, to_world.basis.get_axis(0).cross(to_world.basis.get_axis(2)).normalized()); - - to_poly = to_world.affine_inverse(); - - face_index = p_face; - - for (int i = 0; i < 3; i++) { - - Point p; - Vector3 localp = to_poly.xform(va[i]); - p.point.x = localp.x; - p.point.y = localp.y; - p.uv = p_brush->faces[p_face].uvs[i]; - - points.push_back(p); - - ///edge - - Edge e; - e.points[0] = i; - e.points[1] = (i + 1) % 3; - e.outer = true; - edges.push_back(e); - } - - smooth = p_brush->faces[p_face].smooth; - invert = p_brush->faces[p_face].invert; - - if (p_brush->faces[p_face].material != -1) { - material = p_brush->materials[p_brush->faces[p_face].material]; - } - - base_edges = 3; -} - -static Vector2 interpolate_uv(const Vector2 &p_vertex_a, const Vector2 &p_vertex_b, const Vector2 &p_vertex_c, const Vector2 &p_uv_a, const Vector2 &p_uv_c) { - - float len_a_c = (p_vertex_c - p_vertex_a).length(); - if (len_a_c < CMP_EPSILON) { - return p_uv_a; - } - - float len_a_b = (p_vertex_b - p_vertex_a).length(); - - float c = len_a_b / len_a_c; - - return p_uv_a.linear_interpolate(p_uv_c, c); -} - -static Vector2 interpolate_triangle_uv(const Vector2 &p_pos, const Vector2 *p_vtx, const Vector2 *p_uv) { - - if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) { - return p_uv[0]; - } - if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) { - return p_uv[1]; - } - if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) { - return p_uv[2]; - } - - Vector2 v0 = p_vtx[1] - p_vtx[0]; - Vector2 v1 = p_vtx[2] - p_vtx[0]; - Vector2 v2 = p_pos - p_vtx[0]; - - float d00 = v0.dot(v0); - float d01 = v0.dot(v1); - float d11 = v1.dot(v1); - float d20 = v2.dot(v0); - float d21 = v2.dot(v1); - float denom = (d00 * d11 - d01 * d01); - if (denom == 0) { - return p_uv[0]; - } - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0f - v - w; - - return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; -} - -void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_face, const Vector2 *segment, MeshMerge &mesh_merge, bool p_for_B) { - - //keep track of what was inserted - Vector<int> inserted_points; - - //keep track of point indices for what was inserted, allowing reuse of points. - int segment_idx[2] = { -1, -1 }; - - //check if edge and poly share a vertex, of so, assign it to segment_idx - for (int i = 0; i < points.size(); i++) { - for (int j = 0; j < 2; j++) { - if (segment[j].is_equal_approx(points[i].point)) { - segment_idx[j] = i; - inserted_points.push_back(i); - break; - } - } - } - - //check if both segment points are shared with other vertices - if (segment_idx[0] != -1 && segment_idx[1] != -1) { - - if (segment_idx[0] == segment_idx[1]) { - return; //segment was too tiny, both mapped to same point - } - - bool found = false; - - //check if the segment already exists - for (int i = 0; i < edges.size(); i++) { +// CSGBrushOperation - if ( - (edges[i].points[0] == segment_idx[0] && edges[i].points[1] == segment_idx[1]) || - (edges[i].points[0] == segment_idx[1] && edges[i].points[1] == segment_idx[0])) { - found = true; - break; +void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap) { + // Check for face collisions and add necessary faces. + Build2DFaceCollection build2DFaceCollection; + for (int i = 0; i < p_brush_a.faces.size(); i++) { + for (int j = 0; j < p_brush_b.faces.size(); j++) { + if (p_brush_a.faces[i].aabb.intersects_inclusive(p_brush_b.faces[j].aabb)) { + update_faces(p_brush_a, i, p_brush_b, j, build2DFaceCollection, p_vertex_snap); } } - - if (found) { - //it does already exist, do nothing - return; - } - - //directly add the new segment - Edge new_edge; - new_edge.points[0] = segment_idx[0]; - new_edge.points[1] = segment_idx[1]; - edges.push_back(new_edge); - return; } - //check edge by edge against the segment points to see if intersects - - for (int i = 0; i < base_edges; i++) { - - //if a point is shared with one of the edge points, then this edge must not be tested, as it will result in a numerical precision error. - bool edge_valid = true; - for (int j = 0; j < 2; j++) { - - if (edges[i].points[0] == segment_idx[0] || edges[i].points[1] == segment_idx[1] || edges[i].points[0] == segment_idx[1] || edges[i].points[1] == segment_idx[0]) { - edge_valid = false; //segment has this point, can't check against this - break; - } - } - - if (!edge_valid) //already hit a point in this edge, so don't test it - continue; - - //see if either points are within the edge isntead of crossing it - Vector2 res; - bool found = false; - int assign_segment_id = -1; - - for (int j = 0; j < 2; j++) { - - Vector2 edgeseg[2] = { points[edges[i].points[0]].point, points[edges[i].points[1]].point }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg); - - if (closest.is_equal_approx(segment[j])) { - //point rest of this edge - res = closest; - found = true; - assign_segment_id = j; - } - } + // Add faces to MeshMerge. + MeshMerge mesh_merge; + mesh_merge.vertex_snap = p_vertex_snap; - //test if the point crosses the edge - if (!found && Geometry::segment_intersects_segment_2d(segment[0], segment[1], points[edges[i].points[0]].point, points[edges[i].points[1]].point, &res)) { - //point does cross the edge - found = true; + for (int i = 0; i < p_brush_a.faces.size(); i++) { + Ref<Material> material; + if (p_brush_a.faces[i].material != -1) { + material = p_brush_a.materials[p_brush_a.faces[i].material]; } - //check whether an intersection against the segment happened - if (found) { - - //It did! so first, must slice the segment - Point new_point; - new_point.point = res; - //make sure to interpolate UV too - new_point.uv = interpolate_uv(points[edges[i].points[0]].point, new_point.point, points[edges[i].points[1]].point, points[edges[i].points[0]].uv, points[edges[i].points[1]].uv); - - int point_idx = points.size(); - points.push_back(new_point); - - //split the edge in 2 - Edge new_edge; - new_edge.points[0] = edges[i].points[0]; - new_edge.points[1] = point_idx; - new_edge.outer = edges[i].outer; - edges.write[i].points[0] = point_idx; - edges.insert(i, new_edge); - i++; //skip newly inserted edge - base_edges++; //will need an extra one in the base triangle - if (assign_segment_id >= 0) { - //point did split a segment, so make sure to remember this - segment_idx[assign_segment_id] = point_idx; + if (build2DFaceCollection.build2DFacesA.has(i)) { + build2DFaceCollection.build2DFacesA[i].addFacesToMesh(mesh_merge, p_brush_a.faces[i].smooth, p_brush_a.faces[i].invert, material, false); + } else { + Vector3 points[3]; + Vector2 uvs[3]; + for (int j = 0; j < 3; j++) { + points[j] = p_brush_a.faces[i].vertices[j]; + uvs[j] = p_brush_a.faces[i].uvs[j]; } - inserted_points.push_back(point_idx); + mesh_merge.add_face(points, uvs, p_brush_a.faces[i].smooth, p_brush_a.faces[i].invert, material, false); } } - //final step: after cutting the original triangle, try to see if we can still insert - //this segment - - //if already inserted two points, just use them for a segment - - if (inserted_points.size() >= 2) { //should never be >2 on non-manifold geometry, but cope with error - //two points were inserted, create the new edge - Edge new_edge; - new_edge.points[0] = inserted_points[0]; - new_edge.points[1] = inserted_points[1]; - edges.push_back(new_edge); - return; - } - - // One or no points were inserted (besides splitting), so try to see if extra points can be placed inside the triangle. - // This needs to be done here, after the previous tests were exhausted - for (int i = 0; i < 2; i++) { - - if (segment_idx[i] != -1) - continue; //already assigned to something, so skip - - //check whether one of the segment endpoints is inside the triangle. If it is, this points needs to be inserted - if (Geometry::is_point_in_triangle(segment[i], points[0].point, points[1].point, points[2].point)) { - - Point new_point; - new_point.point = segment[i]; - - Vector2 point3[3] = { points[0].point, points[1].point, points[2].point }; - Vector2 uv3[3] = { points[0].uv, points[1].uv, points[2].uv }; - - new_point.uv = interpolate_triangle_uv(new_point.point, point3, uv3); - - int point_idx = points.size(); - points.push_back(new_point); - inserted_points.push_back(point_idx); + for (int i = 0; i < p_brush_b.faces.size(); i++) { + Ref<Material> material; + if (p_brush_b.faces[i].material != -1) { + material = p_brush_b.materials[p_brush_b.faces[i].material]; } - } - - //check again whether two points were inserted, if so then create the new edge - if (inserted_points.size() >= 2) { //should never be >2 on non-manifold geometry, but cope with error - Edge new_edge; - new_edge.points[0] = inserted_points[0]; - new_edge.points[1] = inserted_points[1]; - edges.push_back(new_edge); - } -} - -void CSGBrushOperation::BuildPoly::clip(const CSGBrush *p_brush, int p_face, MeshMerge &mesh_merge, bool p_for_B) { - - //Clip function.. find triangle points that will be mapped to the plane and form a segment - Vector2 segment[3]; //2D - - int src_points = 0; - - for (int i = 0; i < 3; i++) { - Vector3 p = p_brush->faces[p_face].vertices[i]; - if (plane.has_point(p)) { - Vector3 pp = plane.project(p); - pp = to_poly.xform(pp); - segment[src_points++] = Vector2(pp.x, pp.y); + if (build2DFaceCollection.build2DFacesB.has(i)) { + build2DFaceCollection.build2DFacesB[i].addFacesToMesh(mesh_merge, p_brush_b.faces[i].smooth, p_brush_b.faces[i].invert, material, true); } else { - Vector3 q = p_brush->faces[p_face].vertices[(i + 1) % 3]; - if (plane.has_point(q)) - continue; //next point is in plane, will be added eventually - if (plane.is_point_over(p) == plane.is_point_over(q)) - continue; // both on same side of the plane, don't add - - Vector3 res; - if (plane.intersects_segment(p, q, &res)) { - res = to_poly.xform(res); - segment[src_points++] = Vector2(res.x, res.y); + Vector3 points[3]; + Vector2 uvs[3]; + for (int j = 0; j < 3; j++) { + points[j] = p_brush_b.faces[i].vertices[j]; + uvs[j] = p_brush_b.faces[i].uvs[j]; } + mesh_merge.add_face(points, uvs, p_brush_b.faces[i].smooth, p_brush_b.faces[i].invert, material, true); } } - //all above or all below, nothing to do. Should not happen though since a precheck was done before. - if (src_points == 0) - return; - - //just one point in plane is not worth doing anything - if (src_points == 1) - return; - - //transform A points to 2D - - if (segment[0].is_equal_approx(segment[1])) - return; //too small - - _clip_segment(p_brush, p_face, segment, mesh_merge, p_for_B); -} - -void CSGBrushOperation::_collision_callback(const CSGBrush *A, int p_face_a, Map<int, BuildPoly> &build_polys_a, const CSGBrush *B, int p_face_b, Map<int, BuildPoly> &build_polys_b, MeshMerge &mesh_merge) { - - //construct a frame of reference for both transforms, in order to do intersection test - Vector3 va[3] = { - A->faces[p_face_a].vertices[0], - A->faces[p_face_a].vertices[1], - A->faces[p_face_a].vertices[2], - }; - Vector3 vb[3] = { - B->faces[p_face_b].vertices[0], - B->faces[p_face_b].vertices[1], - B->faces[p_face_b].vertices[2], - }; - - { - //check if either is a degenerate - if (va[0].is_equal_approx(va[1]) || va[0].is_equal_approx(va[2]) || va[1].is_equal_approx(va[2])) - return; - - if (vb[0].is_equal_approx(vb[1]) || vb[0].is_equal_approx(vb[2]) || vb[1].is_equal_approx(vb[2])) - return; - } + // Mark faces that ended up inside the intersection. + mesh_merge.mark_inside_faces(); - { - //check if points are the same - int equal_count = 0; + // Create new brush and fill with new faces. + r_merged_brush.faces.clear(); - for (int i = 0; i < 3; i++) { + switch (p_operation) { + case OPERATION_UNION: { + int outside_count = 0; - for (int j = 0; j < 3; j++) { - if (va[i].distance_to(vb[j]) < mesh_merge.vertex_snap) { - equal_count++; - break; + for (int i = 0; i < mesh_merge.faces.size(); i++) { + if (mesh_merge.faces[i].inside) { + continue; } + outside_count++; } - } - - //if 2 or 3 points are the same, there is no point in doing anything. They can't - //be clipped either, so add both. - if (equal_count == 2 || equal_count == 3) { - return; - } - } - - // do a quick pre-check for no-intersection using the SAT theorem - - { - - //b under or over a plane - int over_count = 0, in_plane_count = 0, under_count = 0; - Plane plane_a(va[0], va[1], va[2]); - if (plane_a.normal == Vector3()) { - return; //degenerate - } - - for (int i = 0; i < 3; i++) { - if (plane_a.has_point(vb[i])) - in_plane_count++; - else if (plane_a.is_point_over(vb[i])) - over_count++; - else - under_count++; - } - - if (over_count == 0 || under_count == 0) - return; //no intersection, something needs to be under AND over - //a under or over b plane - over_count = 0; - under_count = 0; - in_plane_count = 0; - - Plane plane_b(vb[0], vb[1], vb[2]); - if (plane_b.normal == Vector3()) - return; //degenerate - - for (int i = 0; i < 3; i++) { - if (plane_b.has_point(va[i])) - in_plane_count++; - else if (plane_b.is_point_over(va[i])) - over_count++; - else - under_count++; - } - - if (over_count == 0 || under_count == 0) - return; //no intersection, something needs to be under AND over - - //edge pairs (cross product combinations), see SAT theorem - - for (int i = 0; i < 3; i++) { + r_merged_brush.faces.resize(outside_count); - Vector3 axis_a = (va[i] - va[(i + 1) % 3]).normalized(); - - for (int j = 0; j < 3; j++) { - - Vector3 axis_b = (vb[j] - vb[(j + 1) % 3]).normalized(); - - Vector3 sep_axis = axis_a.cross(axis_b); - if (sep_axis == Vector3()) - continue; //colineal - sep_axis.normalize(); - - real_t min_a = 1e20, max_a = -1e20; - real_t min_b = 1e20, max_b = -1e20; + outside_count = 0; - for (int k = 0; k < 3; k++) { - real_t d = sep_axis.dot(va[k]); - min_a = MIN(min_a, d); - max_a = MAX(max_a, d); - d = sep_axis.dot(vb[k]); - min_b = MIN(min_b, d); - max_b = MAX(max_b, d); + for (int i = 0; i < mesh_merge.faces.size(); i++) { + if (mesh_merge.faces[i].inside) { + continue; } - min_b -= (max_a - min_a) * 0.5; - max_b += (max_a - min_a) * 0.5; - - real_t dmin = min_b - (min_a + max_a) * 0.5; - real_t dmax = max_b - (min_a + max_a) * 0.5; - - if (dmin > CMP_EPSILON || dmax < -CMP_EPSILON) { - return; //does not contain zero, so they don't overlap + for (int j = 0; j < 3; j++) { + r_merged_brush.faces.write[outside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; + r_merged_brush.faces.write[outside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; } - } - } - } - - //if we are still here, it means they most likely intersect, so create BuildPolys if they don't exist - - BuildPoly *poly_a = NULL; - - if (!build_polys_a.has(p_face_a)) { - - BuildPoly bp; - bp.create(A, p_face_a, mesh_merge, false); - build_polys_a[p_face_a] = bp; - } - - poly_a = &build_polys_a[p_face_a]; - - BuildPoly *poly_b = NULL; - - if (!build_polys_b.has(p_face_b)) { - - BuildPoly bp; - bp.create(B, p_face_b, mesh_merge, true); - build_polys_b[p_face_b] = bp; - } - - poly_b = &build_polys_b[p_face_b]; - - //clip each other, this could be improved by using vertex unique IDs (more vertices may be shared instead of using snap) - poly_a->clip(B, p_face_b, mesh_merge, false); - poly_b->clip(A, p_face_a, mesh_merge, true); -} - -void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, int p_from_point, int p_to_point, const Vector<Vector<int> > &vertex_process, Vector<bool> &edge_process, Vector<PolyPoints> &r_poly) { - //this function follows the polygon points counter clockwise and adds them. It creates lists of unique polygons - //every time an unused edge is found, it's pushed to a stack and continues from there. - - List<EdgeSort> edge_stack; - - { - EdgeSort es; - es.angle = 0; //won't be checked here - es.edge = p_edge; - es.prev_point = p_from_point; - es.edge_point = p_to_point; - - edge_stack.push_back(es); - } - - //attempt to empty the stack. - while (edge_stack.size()) { - - EdgeSort e = edge_stack.front()->get(); - edge_stack.pop_front(); - - if (edge_process[e.edge]) { - //nothing to do here - continue; - } - - Vector<int> points; - points.push_back(e.prev_point); - - int prev_point = e.prev_point; - int to_point = e.edge_point; - int current_edge = e.edge; - - edge_process.write[e.edge] = true; //mark as processed - - int limit = p_poly.points.size() * 4; //avoid infinite recursion - - while (to_point != e.prev_point && limit) { - - Vector2 segment[2] = { p_poly.points[prev_point].point, p_poly.points[to_point].point }; - - //construct a basis transform from the segment, which will be used to check the angle - Transform2D t2d; - t2d[0] = (segment[1] - segment[0]).normalized(); //use as Y - t2d[1] = Vector2(-t2d[0].y, t2d[0].x); // use as tangent - t2d[2] = segment[1]; //origin - - if (t2d.basis_determinant() == 0) - break; //abort poly - - t2d.affine_invert(); - - //push all edges found here, they will be sorted by minimum angle later. - Vector<EdgeSort> next_edges; - - for (int i = 0; i < vertex_process[to_point].size(); i++) { - - int edge = vertex_process[to_point][i]; - int opposite_point = p_poly.edges[edge].points[0] == to_point ? p_poly.edges[edge].points[1] : p_poly.edges[edge].points[0]; - if (opposite_point == prev_point) - continue; //not going back - - EdgeSort e2; - Vector2 local_vec = t2d.xform(p_poly.points[opposite_point].point); - e2.angle = -local_vec.angle(); //negate so we can sort by minimum angle - e2.edge = edge; - e2.edge_point = opposite_point; - e2.prev_point = to_point; - - next_edges.push_back(e2); + r_merged_brush.faces.write[outside_count].smooth = mesh_merge.faces[i].smooth; + r_merged_brush.faces.write[outside_count].invert = mesh_merge.faces[i].invert; + r_merged_brush.faces.write[outside_count].material = mesh_merge.faces[i].material_idx; + outside_count++; } - //finally, sort by minimum angle - next_edges.sort(); + r_merged_brush._regen_face_aabbs(); - int next_point = -1; - int next_edge = -1; - - for (int i = 0; i < next_edges.size(); i++) { + } break; - if (i == 0) { - //minimum angle found is the next point - next_point = next_edges[i].edge_point; - next_edge = next_edges[i].edge; + case OPERATION_INTERSECTION: { + int inside_count = 0; - } else { - //the rest are pushed to the stack IF they were not processed yet. - if (!edge_process[next_edges[i].edge]) { - edge_stack.push_back(next_edges[i]); - } + for (int i = 0; i < mesh_merge.faces.size(); i++) { + if (!mesh_merge.faces[i].inside) { + continue; } + inside_count++; } - if (next_edge == -1) { - //did not find anything, may be a dead-end edge (this should normally not happen) - //just flip the direction and go back - next_point = prev_point; - next_edge = current_edge; - } - - points.push_back(to_point); - - prev_point = to_point; - to_point = next_point; - edge_process.write[next_edge] = true; //mark this edge as processed - current_edge = next_edge; - - limit--; - } - - //if more than 2 points were added to the polygon, add it to the list of polygons. - if (points.size() > 2) { - PolyPoints pp; - pp.points = points; - r_poly.push_back(pp); - } - } -} - -void CSGBrushOperation::_add_poly_outline(const BuildPoly &p_poly, int p_from_point, int p_to_point, const Vector<Vector<int> > &vertex_process, Vector<int> &r_outline) { - - //this is the opposite of the function above. It adds polygon outlines instead. - //this is used for triangulating holes. - //no stack is used here because only the bigger outline is interesting. - - r_outline.push_back(p_from_point); - - int prev_point = p_from_point; - int to_point = p_to_point; - - int limit = p_poly.points.size() * 4; //avoid infinite recursion - - while (to_point != p_from_point && limit) { - - Vector2 segment[2] = { p_poly.points[prev_point].point, p_poly.points[to_point].point }; - //again create a transform to compute the angle. - Transform2D t2d; - t2d[0] = (segment[1] - segment[0]).normalized(); //use as Y - t2d[1] = Vector2(-t2d[0].y, t2d[0].x); // use as tangent - t2d[2] = segment[1]; //origin - - if (t2d.basis_determinant() == 0) - break; //abort poly - - t2d.affine_invert(); - - float max_angle = 0; - int next_point_angle = -1; - - for (int i = 0; i < vertex_process[to_point].size(); i++) { - - int edge = vertex_process[to_point][i]; - int opposite_point = p_poly.edges[edge].points[0] == to_point ? p_poly.edges[edge].points[1] : p_poly.edges[edge].points[0]; - if (opposite_point == prev_point) - continue; //not going back - - float angle = -t2d.xform(p_poly.points[opposite_point].point).angle(); - if (next_point_angle == -1 || angle > max_angle) { //same as before but use greater to check. - max_angle = angle; - next_point_angle = opposite_point; - } - } - - if (next_point_angle == -1) { - //go back because no route found - next_point_angle = prev_point; - } - - r_outline.push_back(to_point); - prev_point = to_point; - to_point = next_point_angle; - - limit--; - } -} - -void CSGBrushOperation::_merge_poly(MeshMerge &mesh, int p_face_idx, const BuildPoly &p_poly, bool p_from_b) { + r_merged_brush.faces.resize(inside_count); - //finally, merge the 2D polygon back to 3D - - Vector<Vector<int> > vertex_process; - Vector<bool> edge_process; - - vertex_process.resize(p_poly.points.size()); - edge_process.resize(p_poly.edges.size()); - - //none processed by default - for (int i = 0; i < edge_process.size(); i++) { - edge_process.write[i] = false; - } - - //put edges in points, so points can go through them - for (int i = 0; i < p_poly.edges.size(); i++) { - vertex_process.write[p_poly.edges[i].points[0]].push_back(i); - vertex_process.write[p_poly.edges[i].points[1]].push_back(i); - } - - Vector<PolyPoints> polys; - - //process points that were not processed - for (int i = 0; i < edge_process.size(); i++) { - if (edge_process[i]) - continue; //already processed - - int intersect_poly = -1; - - if (i > 0) { - //this is disconnected, so it's clearly a hole. lets find where it belongs - Vector2 ref_point = p_poly.points[p_poly.edges[i].points[0]].point; - - for (int j = 0; j < polys.size(); j++) { - - //find a point outside poly - Vector2 out_point(-1e20, -1e20); - - const PolyPoints &pp = polys[j]; - - for (int k = 0; k < pp.points.size(); k++) { - Vector2 p = p_poly.points[pp.points[k]].point; - out_point.x = MAX(out_point.x, p.x); - out_point.y = MAX(out_point.y, p.y); - } - - out_point += Vector2(0.12341234, 0.4123412); // move to a random place to avoid direct edge-point chances - - int intersections = 0; - - for (int k = 0; k < pp.points.size(); k++) { - Vector2 p1 = p_poly.points[pp.points[k]].point; - Vector2 p2 = p_poly.points[pp.points[(k + 1) % pp.points.size()]].point; + inside_count = 0; - if (Geometry::segment_intersects_segment_2d(ref_point, out_point, p1, p2, NULL)) { - intersections++; - } + for (int i = 0; i < mesh_merge.faces.size(); i++) { + if (!mesh_merge.faces[i].inside) { + continue; } - if (intersections % 2 == 1) { - //hole is inside this poly - intersect_poly = j; - break; + for (int j = 0; j < 3; j++) { + r_merged_brush.faces.write[inside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; + r_merged_brush.faces.write[inside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; } - } - } - - if (intersect_poly != -1) { - //must add this as a hole - Vector<int> outline; - _add_poly_outline(p_poly, p_poly.edges[i].points[0], p_poly.edges[i].points[1], vertex_process, outline); - if (outline.size() > 1) { - polys.write[intersect_poly].holes.push_back(outline); + r_merged_brush.faces.write[inside_count].smooth = mesh_merge.faces[i].smooth; + r_merged_brush.faces.write[inside_count].invert = mesh_merge.faces[i].invert; + r_merged_brush.faces.write[inside_count].material = mesh_merge.faces[i].material_idx; + inside_count++; } - } - _add_poly_points(p_poly, i, p_poly.edges[i].points[0], p_poly.edges[i].points[1], vertex_process, edge_process, polys); - } - - //get rid of holes, not the most optiomal way, but also not a common case at all to be inoptimal - for (int i = 0; i < polys.size(); i++) { - - if (!polys[i].holes.size()) - continue; - - //repeat until no more holes are left to be merged - while (polys[i].holes.size()) { - - //try to merge a hole with the outline - bool added_hole = false; - - for (int j = 0; j < polys[i].holes.size(); j++) { - - //try hole vertices - int with_outline_vertex = -1; - int from_hole_vertex = -1; - - bool found = false; - - for (int k = 0; k < polys[i].holes[j].size(); k++) { - - int from_idx = polys[i].holes[j][k]; - Vector2 from = p_poly.points[from_idx].point; - - //try a segment from hole vertex to outline vertices - from_hole_vertex = k; - - bool valid = true; - - for (int l = 0; l < polys[i].points.size(); l++) { - int to_idx = polys[i].points[l]; - Vector2 to = p_poly.points[to_idx].point; - with_outline_vertex = l; + r_merged_brush._regen_face_aabbs(); - //try against outline (other points) first - - valid = true; - - for (int m = 0; m < polys[i].points.size(); m++) { - - int m_next = (m + 1) % polys[i].points.size(); - if (m == with_outline_vertex || m_next == with_outline_vertex) //do not test with edges that share this point - continue; - - if (Geometry::segment_intersects_segment_2d(from, to, p_poly.points[polys[i].points[m]].point, p_poly.points[polys[i].points[m_next]].point, NULL)) { - valid = false; - break; - } - } - - if (!valid) - continue; - - //try against all holes including self - - for (int m = 0; m < polys[i].holes.size(); m++) { - - for (int n = 0; n < polys[i].holes[m].size(); n++) { - - int n_next = (n + 1) % polys[i].holes[m].size(); - if (m == j && (n == from_hole_vertex || n_next == from_hole_vertex)) //contains vertex being tested from current hole, skip - continue; - - if (Geometry::segment_intersects_segment_2d(from, to, p_poly.points[polys[i].holes[m][n]].point, p_poly.points[polys[i].holes[m][n_next]].point, NULL)) { - valid = false; - break; - } - } - - if (!valid) - break; - } + } break; - if (valid) //all passed! exit loop - break; - else - continue; //something went wrong, go on. - } + case OPERATION_SUBSTRACTION: { + int face_count = 0; - if (valid) { - found = true; //if in the end this was valid, use it - break; - } + for (int i = 0; i < mesh_merge.faces.size(); i++) { + if (mesh_merge.faces[i].from_b && !mesh_merge.faces[i].inside) { + continue; } - - if (found) { - - //hook this hole with outline, and remove from list of holes - - //duplicate point - int insert_at = with_outline_vertex; - int point = polys[i].points[insert_at]; - polys.write[i].points.insert(insert_at, point); - insert_at++; - //insert all others, outline should be backwards (must check) - int holesize = polys[i].holes[j].size(); - for (int k = 0; k <= holesize; k++) { - int idx = (from_hole_vertex + k) % holesize; - int point2 = polys[i].holes[j][idx]; - polys.write[i].points.insert(insert_at, point2); - insert_at++; - } - - added_hole = true; - polys.write[i].holes.remove(j); - break; //got rid of hole, break and continue + if (!mesh_merge.faces[i].from_b && mesh_merge.faces[i].inside) { + continue; } + face_count++; } - ERR_BREAK(!added_hole); - } - } - - //triangulate polygons + r_merged_brush.faces.resize(face_count); - for (int i = 0; i < polys.size(); i++) { - - Vector<Vector2> vertices; - vertices.resize(polys[i].points.size()); - for (int j = 0; j < vertices.size(); j++) { - vertices.write[j] = p_poly.points[polys[i].points[j]].point; - } + face_count = 0; - Vector<int> indices = Geometry::triangulate_polygon(vertices); + for (int i = 0; i < mesh_merge.faces.size(); i++) { + if (mesh_merge.faces[i].from_b && !mesh_merge.faces[i].inside) { + continue; + } + if (!mesh_merge.faces[i].from_b && mesh_merge.faces[i].inside) { + continue; + } - for (int j = 0; j < indices.size(); j += 3) { + for (int j = 0; j < 3; j++) { + r_merged_brush.faces.write[face_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; + r_merged_brush.faces.write[face_count].uvs[j] = mesh_merge.faces[i].uvs[j]; + } - //obtain the vertex + if (mesh_merge.faces[i].from_b) { + //invert facing of insides of B + SWAP(r_merged_brush.faces.write[face_count].vertices[1], r_merged_brush.faces.write[face_count].vertices[2]); + SWAP(r_merged_brush.faces.write[face_count].uvs[1], r_merged_brush.faces.write[face_count].uvs[2]); + } - Vector3 face[3]; - Vector2 uv[3]; - float cp = Geometry::vec2_cross(p_poly.points[polys[i].points[indices[j + 0]]].point, p_poly.points[polys[i].points[indices[j + 1]]].point, p_poly.points[polys[i].points[indices[j + 2]]].point); - if (Math::abs(cp) < CMP_EPSILON) - continue; + r_merged_brush.faces.write[face_count].smooth = mesh_merge.faces[i].smooth; + r_merged_brush.faces.write[face_count].invert = mesh_merge.faces[i].invert; + r_merged_brush.faces.write[face_count].material = mesh_merge.faces[i].material_idx; + face_count++; + } - for (int k = 0; k < 3; k++) { + r_merged_brush._regen_face_aabbs(); - Vector2 p = p_poly.points[polys[i].points[indices[j + k]]].point; - face[k] = p_poly.to_world.xform(Vector3(p.x, p.y, 0)); - uv[k] = p_poly.points[polys[i].points[indices[j + k]]].uv; - } + } break; + } - mesh.add_face(face[0], face[1], face[2], uv[0], uv[1], uv[2], p_poly.smooth, p_poly.invert, p_poly.material, p_from_b); - } + // Update the list of materials. + r_merged_brush.materials.resize(mesh_merge.materials.size()); + for (const Map<Ref<Material>, int>::Element *E = mesh_merge.materials.front(); E; E = E->next()) { + r_merged_brush.materials.write[E->get()] = E->key(); } } -//use a limit to speed up bvh and limit the depth -#define BVH_LIMIT 8 +// CSGBrushOperation::MeshMerge -int CSGBrushOperation::MeshMerge::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, int p_depth, int &max_depth, int &max_alloc) { +// Use a limit to speed up bvh and limit the depth. +#define BVH_LIMIT 8 - if (p_depth > max_depth) { - max_depth = p_depth; +int CSGBrushOperation::MeshMerge::_create_bvh(FaceBVH *facebvhptr, FaceBVH **facebvhptrptr, int p_from, int p_size, int p_depth, int &r_max_depth, int &r_max_alloc) { + if (p_depth > r_max_depth) { + r_max_depth = p_depth; } if (p_size == 0) { - return -1; - } else if (p_size <= BVH_LIMIT) { + } + if (p_size <= BVH_LIMIT) { for (int i = 0; i < p_size - 1; i++) { - p_bb[p_from + i]->next = p_bb[p_from + i + 1] - p_bvh; + facebvhptrptr[p_from + i]->next = facebvhptrptr[p_from + i + 1] - facebvhptr; } - return p_bb[p_from] - p_bvh; + return facebvhptrptr[p_from] - facebvhptr; } AABB aabb; - aabb = p_bb[p_from]->aabb; + aabb = facebvhptrptr[p_from]->aabb; for (int i = 1; i < p_size; i++) { - - aabb.merge_with(p_bb[p_from + i]->aabb); + aabb.merge_with(facebvhptrptr[p_from + i]->aabb); } int li = aabb.get_longest_axis_index(); switch (li) { - case Vector3::AXIS_X: { - SortArray<BVH *, BVHCmpX> sort_x; - sort_x.nth_element(0, p_size, p_size / 2, &p_bb[p_from]); + SortArray<FaceBVH *, FaceBVHCmpX> sort_x; + sort_x.nth_element(0, p_size, p_size / 2, &facebvhptrptr[p_from]); //sort_x.sort(&p_bb[p_from],p_size); } break; + case Vector3::AXIS_Y: { - SortArray<BVH *, BVHCmpY> sort_y; - sort_y.nth_element(0, p_size, p_size / 2, &p_bb[p_from]); + SortArray<FaceBVH *, FaceBVHCmpY> sort_y; + sort_y.nth_element(0, p_size, p_size / 2, &facebvhptrptr[p_from]); //sort_y.sort(&p_bb[p_from],p_size); } break; + case Vector3::AXIS_Z: { - SortArray<BVH *, BVHCmpZ> sort_z; - sort_z.nth_element(0, p_size, p_size / 2, &p_bb[p_from]); + SortArray<FaceBVH *, FaceBVHCmpZ> sort_z; + sort_z.nth_element(0, p_size, p_size / 2, &facebvhptrptr[p_from]); //sort_z.sort(&p_bb[p_from],p_size); - } break; } - int left = _create_bvh(p_bvh, p_bb, p_from, p_size / 2, p_depth + 1, max_depth, max_alloc); - int right = _create_bvh(p_bvh, p_bb, p_from + p_size / 2, p_size - p_size / 2, p_depth + 1, max_depth, max_alloc); + int left = _create_bvh(facebvhptr, facebvhptrptr, p_from, p_size / 2, p_depth + 1, r_max_depth, r_max_alloc); + int right = _create_bvh(facebvhptr, facebvhptrptr, p_from + p_size / 2, p_size - p_size / 2, p_depth + 1, r_max_depth, r_max_alloc); - int index = max_alloc++; - BVH *_new = &p_bvh[index]; + int index = r_max_alloc++; + FaceBVH *_new = &facebvhptr[index]; _new->aabb = aabb; _new->center = aabb.position + aabb.size * 0.5; _new->face = -1; @@ -1073,7 +518,28 @@ int CSGBrushOperation::MeshMerge::_create_bvh(BVH *p_bvh, BVH **p_bb, int p_from return index; } -int CSGBrushOperation::MeshMerge::_bvh_count_intersections(BVH *bvhptr, int p_max_depth, int p_bvh_first, const Vector3 &p_begin, const Vector3 &p_end, int p_exclude) const { +void CSGBrushOperation::MeshMerge::_add_distance(List<real_t> &r_intersectionsA, List<real_t> &r_intersectionsB, bool p_from_B, real_t p_distance) const { + 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::abs(**E - p_distance) < vertex_snap) { + return; + } + } + + intersections.push_back(p_distance); +} + +bool CSGBrushOperation::MeshMerge::_bvh_inside(FaceBVH *facebvhptr, int p_max_depth, int p_bvh_first, int p_face_idx) const { + Face face = faces[p_face_idx]; + Vector3 face_points[3] = { + points[face.points[0]], + points[face.points[1]], + points[face.points[2]] + }; + Vector3 face_center = (face_points[0] + face_points[1] + face_points[2]) / 3.0; + Vector3 face_normal = Plane(face_points[0], face_points[1], face_points[2]).normal; uint32_t *stack = (uint32_t *)alloca(sizeof(int) * p_max_depth); @@ -1084,226 +550,206 @@ int CSGBrushOperation::MeshMerge::_bvh_count_intersections(BVH *bvhptr, int p_ma VISIT_DONE_BIT = 3, VISITED_BIT_SHIFT = 29, NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1, - VISITED_BIT_MASK = ~NODE_IDX_MASK, - + VISITED_BIT_MASK = ~NODE_IDX_MASK }; - int intersections = 0; + List<real_t> intersectionsA; + List<real_t> intersectionsB; int level = 0; - - const Vector3 *vertexptr = points.ptr(); - const Face *facesptr = faces.ptr(); - AABB segment_aabb; - segment_aabb.position = p_begin; - segment_aabb.expand_to(p_end); - int pos = p_bvh_first; - stack[0] = pos; - while (true) { + while (true) { uint32_t node = stack[level] & NODE_IDX_MASK; - const BVH &b = bvhptr[node]; + const FaceBVH *current_facebvhptr = &(facebvhptr[node]); bool done = false; switch (stack[level] >> VISITED_BIT_SHIFT) { case TEST_AABB_BIT: { - - if (b.face >= 0) { - - const BVH *bp = &b; - - while (bp) { - - bool valid = segment_aabb.intersects(bp->aabb) && bp->aabb.intersects_segment(p_begin, p_end); - - if (valid && p_exclude != bp->face) { - const Face &s = facesptr[bp->face]; - Face3 f3(vertexptr[s.points[0]], vertexptr[s.points[1]], vertexptr[s.points[2]]); - - Vector3 res; - - if (f3.intersects_segment(p_begin, p_end, &res)) { - intersections++; + if (current_facebvhptr->face >= 0) { + while (current_facebvhptr) { + if (p_face_idx != current_facebvhptr->face && + current_facebvhptr->aabb.intersects_ray(face_center, face_normal)) { + const Face ¤t_face = faces[current_facebvhptr->face]; + Vector3 current_points[3] = { + points[current_face.points[0]], + points[current_face.points[1]], + points[current_face.points[2]] + }; + Vector3 current_normal = Plane(current_points[0], current_points[1], current_points[2]).normal; + Vector3 intersection_point; + + // Check if faces are co-planar. + if ((current_normal - face_normal).length_squared() < CMP_EPSILON2 && + is_point_in_triangle(face_center, current_points)) { + // Only add an intersection if checking a B face. + if (face.from_b) { + _add_distance(intersectionsA, intersectionsB, current_face.from_b, 0); + } + } else if (ray_intersects_triangle(face_center, face_normal, current_points, CMP_EPSILON, intersection_point)) { + real_t distance = (intersection_point - face_center).length(); + _add_distance(intersectionsA, intersectionsB, current_face.from_b, distance); } } - if (bp->next != -1) { - bp = &bvhptr[bp->next]; + + if (current_facebvhptr->next != -1) { + current_facebvhptr = &facebvhptr[current_facebvhptr->next]; } else { - bp = NULL; + current_facebvhptr = nullptr; } } stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; } else { - - bool valid = segment_aabb.intersects(b.aabb) && b.aabb.intersects_segment(p_begin, p_end); + bool valid = current_facebvhptr->aabb.intersects_ray(face_center, face_normal); if (!valid) { - stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - } else { stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node; } } continue; } - case VISIT_LEFT_BIT: { + case VISIT_LEFT_BIT: { stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node; - stack[level + 1] = b.left | TEST_AABB_BIT; + stack[level + 1] = current_facebvhptr->left | TEST_AABB_BIT; level++; continue; } - case VISIT_RIGHT_BIT: { + case VISIT_RIGHT_BIT: { stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node; - stack[level + 1] = b.right | TEST_AABB_BIT; + stack[level + 1] = current_facebvhptr->right | TEST_AABB_BIT; level++; continue; } - case VISIT_DONE_BIT: { + case VISIT_DONE_BIT: { if (level == 0) { done = true; break; - } else + } else { level--; + } continue; } } - if (done) + if (done) { break; + } } - return intersections; + // Inside if face normal intersects other faces an odd number of times. + return (intersectionsA.size() + intersectionsB.size()) & 1; } void CSGBrushOperation::MeshMerge::mark_inside_faces() { + // Mark faces that are inside. This helps later do the boolean ops when merging. + // This approach is very brute force with a bunch of optimizations, + // such as BVH and pre AABB intersection test. - // mark faces that are inside. This helps later do the boolean ops when merging. - // this approach is very brute force (with a bunch of optimizatios, such as BVH and pre AABB intersection test) + Vector<FaceBVH> bvhvec; + bvhvec.resize(faces.size() * 3); // Will never be larger than this (TODO: Make better) + FaceBVH *facebvh = bvhvec.ptrw(); - AABB aabb; - - for (int i = 0; i < points.size(); i++) { - if (i == 0) { - aabb.position = points[i]; - } else { - aabb.expand_to(points[i]); - } - } - - float max_distance = aabb.size.length() * 1.2; - - Vector<BVH> bvhvec; - bvhvec.resize(faces.size() * 3); //will never be larger than this (todo make better) - BVH *bvh = bvhvec.ptrw(); - - AABB faces_a; - AABB faces_b; + AABB aabb_a; + AABB aabb_b; bool first_a = true; bool first_b = true; for (int i = 0; i < faces.size(); i++) { - bvh[i].left = -1; - bvh[i].right = -1; - bvh[i].face = i; - bvh[i].aabb.position = points[faces[i].points[0]]; - bvh[i].aabb.expand_to(points[faces[i].points[1]]); - bvh[i].aabb.expand_to(points[faces[i].points[2]]); - bvh[i].center = bvh[i].aabb.position + bvh[i].aabb.size * 0.5; - bvh[i].next = -1; + facebvh[i].left = -1; + facebvh[i].right = -1; + facebvh[i].face = i; + facebvh[i].aabb.position = points[faces[i].points[0]]; + facebvh[i].aabb.expand_to(points[faces[i].points[1]]); + facebvh[i].aabb.expand_to(points[faces[i].points[2]]); + facebvh[i].center = facebvh[i].aabb.position + facebvh[i].aabb.size * 0.5; + facebvh[i].aabb.grow_by(vertex_snap); + facebvh[i].next = -1; + if (faces[i].from_b) { if (first_b) { - faces_b = bvh[i].aabb; + aabb_b = facebvh[i].aabb; first_b = false; } else { - faces_b.merge_with(bvh[i].aabb); + aabb_b.merge_with(facebvh[i].aabb); } } else { if (first_a) { - faces_a = bvh[i].aabb; + aabb_a = facebvh[i].aabb; first_a = false; } else { - faces_a.merge_with(bvh[i].aabb); + aabb_a.merge_with(facebvh[i].aabb); } } } - AABB intersection_aabb = faces_a.intersection(faces_b); - intersection_aabb.grow_by(intersection_aabb.get_longest_axis_size() * 0.01); //grow a little, avoid numerical error + AABB intersection_aabb = aabb_a.intersection(aabb_b); - if (intersection_aabb.size == Vector3()) //AABB do not intersect, so neither do shapes. + // Check if shape AABBs intersect. + if (intersection_aabb.size == Vector3()) { return; + } - Vector<BVH *> bvhtrvec; + Vector<FaceBVH *> bvhtrvec; bvhtrvec.resize(faces.size()); - BVH **bvhptr = bvhtrvec.ptrw(); + FaceBVH **bvhptr = bvhtrvec.ptrw(); for (int i = 0; i < faces.size(); i++) { - - bvhptr[i] = &bvh[i]; + bvhptr[i] = &facebvh[i]; } int max_depth = 0; int max_alloc = faces.size(); - _create_bvh(bvh, bvhptr, 0, faces.size(), 1, max_depth, max_alloc); + _create_bvh(facebvh, bvhptr, 0, faces.size(), 1, max_depth, max_alloc); for (int i = 0; i < faces.size(); i++) { + // Check if face AABB intersects the intersection AABB. + if (!intersection_aabb.intersects_inclusive(facebvh[i].aabb)) { + continue; + } - if (!intersection_aabb.intersects(bvh[i].aabb)) - continue; //not in AABB intersection, so not in face intersection - Vector3 center = points[faces[i].points[0]]; - center += points[faces[i].points[1]]; - center += points[faces[i].points[2]]; - center /= 3.0; - - Plane plane(points[faces[i].points[0]], points[faces[i].points[1]], points[faces[i].points[2]]); - Vector3 target = center + plane.normal * max_distance + Vector3(0.0001234, 0.000512, 0.00013423); //reduce chance of edge hits by doing a small increment - - int intersections = _bvh_count_intersections(bvh, max_depth, max_alloc - 1, center, target, i); - - if (intersections & 1) { + if (_bvh_inside(facebvh, max_depth, max_alloc - 1, i)) { faces.write[i].inside = true; } } } -void CSGBrushOperation::MeshMerge::add_face(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector2 &p_uv_a, const Vector2 &p_uv_b, const Vector2 &p_uv_c, bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) { - - Vector3 src_points[3] = { p_a, p_b, p_c }; - Vector2 src_uvs[3] = { p_uv_a, p_uv_b, p_uv_c }; +void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vector2 p_uvs[], bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) { int indices[3]; for (int i = 0; i < 3; i++) { - VertexKey vk; - vk.x = int((double(src_points[i].x) + double(vertex_snap) * 0.31234) / double(vertex_snap)); - vk.y = int((double(src_points[i].y) + double(vertex_snap) * 0.31234) / double(vertex_snap)); - vk.z = int((double(src_points[i].z) + double(vertex_snap) * 0.31234) / double(vertex_snap)); + vk.x = int((double(p_points[i].x) + double(vertex_snap) * 0.31234) / double(vertex_snap)); + vk.y = int((double(p_points[i].y) + double(vertex_snap) * 0.31234) / double(vertex_snap)); + vk.z = int((double(p_points[i].z) + double(vertex_snap) * 0.31234) / double(vertex_snap)); int res; if (snap_cache.lookup(vk, res)) { indices[i] = res; } else { indices[i] = points.size(); - points.push_back(src_points[i]); + points.push_back(p_points[i]); snap_cache.set(vk, indices[i]); } } - if (indices[0] == indices[2] || indices[0] == indices[1] || indices[1] == indices[2]) - return; //not adding degenerate + // Don't add degenerate faces. + if (indices[0] == indices[2] || indices[0] == indices[1] || indices[1] == indices[2]) { + return; + } MeshMerge::Face face; face.from_b = p_from_b; face.inside = false; face.smooth = p_smooth; face.invert = p_invert; + if (p_material.is_valid()) { if (!materials.has(p_material)) { face.material_idx = materials.size(); @@ -1316,205 +762,713 @@ void CSGBrushOperation::MeshMerge::add_face(const Vector3 &p_a, const Vector3 &p } for (int k = 0; k < 3; k++) { - face.points[k] = indices[k]; - face.uvs[k] = src_uvs[k]; - ; + face.uvs[k] = p_uvs[k]; } faces.push_back(face); } -void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_A, const CSGBrush &p_B, CSGBrush &result, float p_snap) { +// CSGBrushOperation::Build2DFaces - CallbackData cd; - cd.self = this; - cd.A = &p_A; - cd.B = &p_B; - - MeshMerge mesh_merge; - mesh_merge.vertex_snap = p_snap; - - //check intersections between faces. Use AABB to speed up precheck - //this generates list of buildpolys and clips them. - //this was originally BVH optimized, but its not really worth it. - for (int i = 0; i < p_A.faces.size(); i++) { - cd.face_a = i; - for (int j = 0; j < p_B.faces.size(); j++) { - if (p_A.faces[i].aabb.intersects(p_B.faces[j].aabb)) { - _collision_callback(&p_A, i, cd.build_polys_A, &p_B, j, cd.build_polys_B, mesh_merge); - } +int CSGBrushOperation::Build2DFaces::_get_point_idx(const Vector2 &p_point) { + for (int vertex_idx = 0; vertex_idx < vertices.size(); ++vertex_idx) { + if ((p_point - vertices[vertex_idx].point).length_squared() < vertex_snap2) { + return vertex_idx; } } + return -1; +} - //merge the already cliped polys back to 3D - for (Map<int, BuildPoly>::Element *E = cd.build_polys_A.front(); E; E = E->next()) { - _merge_poly(mesh_merge, E->key(), E->get(), false); +int CSGBrushOperation::Build2DFaces::_add_vertex(const Vertex2D &p_vertex) { + // Check if vertex exists. + int vertex_id = _get_point_idx(p_vertex.point); + if (vertex_id != -1) { + return vertex_id; } - for (Map<int, BuildPoly>::Element *E = cd.build_polys_B.front(); E; E = E->next()) { - _merge_poly(mesh_merge, E->key(), E->get(), true); - } + vertices.push_back(p_vertex); + return vertices.size() - 1; +} - //merge the non clipped faces back +void CSGBrushOperation::Build2DFaces::_add_vertex_idx_sorted(Vector<int> &r_vertex_indices, int p_new_vertex_index) { + if (p_new_vertex_index >= 0 && r_vertex_indices.find(p_new_vertex_index) == -1) { + ERR_FAIL_COND_MSG(p_new_vertex_index >= vertices.size(), "Invalid vertex index."); - for (int i = 0; i < p_A.faces.size(); i++) { + // The first vertex. + if (r_vertex_indices.size() == 0) { + // Simply add it. + r_vertex_indices.push_back(p_new_vertex_index); + return; + } - if (cd.build_polys_A.has(i)) - continue; //made from buildpoly, skipping + // The second vertex. + if (r_vertex_indices.size() == 1) { + Vector2 first_point = vertices[r_vertex_indices[0]].point; + Vector2 new_point = vertices[p_new_vertex_index].point; - Vector3 points[3]; - Vector2 uvs[3]; - for (int j = 0; j < 3; j++) { - points[j] = p_A.faces[i].vertices[j]; - uvs[j] = p_A.faces[i].uvs[j]; + // Sort along the axis with the greatest difference. + int axis = 0; + if (Math::abs(new_point.x - first_point.x) < Math::abs(new_point.y - first_point.y)) { + axis = 1; + } + + // Add it to the beginning or the end appropriately. + if (new_point[axis] < first_point[axis]) { + r_vertex_indices.insert(0, p_new_vertex_index); + } else { + r_vertex_indices.push_back(p_new_vertex_index); + } + + return; } - Ref<Material> material; - if (p_A.faces[i].material != -1) { - material = p_A.materials[p_A.faces[i].material]; + + // Third or later vertices. + Vector2 first_point = vertices[r_vertex_indices[0]].point; + Vector2 last_point = vertices[r_vertex_indices[r_vertex_indices.size() - 1]].point; + Vector2 new_point = vertices[p_new_vertex_index].point; + + // Determine axis being sorted against i.e. the axis with the greatest difference. + int axis = 0; + if (Math::abs(last_point.x - first_point.x) < Math::abs(last_point.y - first_point.y)) { + axis = 1; + } + + // Insert the point at the appropriate index. + for (int insert_idx = 0; insert_idx < r_vertex_indices.size(); ++insert_idx) { + Vector2 insert_point = vertices[r_vertex_indices[insert_idx]].point; + if (new_point[axis] < insert_point[axis]) { + r_vertex_indices.insert(insert_idx, p_new_vertex_index); + return; + } } - mesh_merge.add_face(points[0], points[1], points[2], uvs[0], uvs[1], uvs[2], p_A.faces[i].smooth, p_A.faces[i].invert, material, false); + + // New largest, add it to the end. + r_vertex_indices.push_back(p_new_vertex_index); } +} - for (int i = 0; i < p_B.faces.size(); i++) { +void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_indices) { + int segments = p_segment_indices.size() - 1; + if (segments < 2) { + return; + } - if (cd.build_polys_B.has(i)) - continue; //made from buildpoly, skipping + // Faces around an inner vertex are merged by moving the inner vertex to the first vertex. + for (int sorted_idx = 1; sorted_idx < segments; ++sorted_idx) { + int closest_idx = 0; + int inner_idx = p_segment_indices[sorted_idx]; - Vector3 points[3]; - Vector2 uvs[3]; - for (int j = 0; j < 3; j++) { - points[j] = p_B.faces[i].vertices[j]; - uvs[j] = p_B.faces[i].uvs[j]; + if (sorted_idx > segments / 2) { + // Merge to other segment end. + closest_idx = segments; + // Reverse the merge order. + inner_idx = p_segment_indices[segments + segments / 2 - sorted_idx]; } - Ref<Material> material; - if (p_B.faces[i].material != -1) { - material = p_B.materials[p_B.faces[i].material]; + + // Find the mergeable faces. + Vector<int> merge_faces_idx; + Vector<Face2D> merge_faces; + Vector<int> merge_faces_inner_vertex_idx; + for (int face_idx = 0; face_idx < faces.size(); ++face_idx) { + for (int face_vertex_idx = 0; face_vertex_idx < 3; ++face_vertex_idx) { + if (faces[face_idx].vertex_idx[face_vertex_idx] == inner_idx) { + merge_faces_idx.push_back(face_idx); + merge_faces.push_back(faces[face_idx]); + merge_faces_inner_vertex_idx.push_back(face_vertex_idx); + } + } } - mesh_merge.add_face(points[0], points[1], points[2], uvs[0], uvs[1], uvs[2], p_B.faces[i].smooth, p_B.faces[i].invert, material, true); - } - //mark faces that ended up inside the intersection - mesh_merge.mark_inside_faces(); + Vector<int> degenerate_points; - //regen new brush to start filling it again - result.clear(); + // Create the new faces. + for (int merge_idx = 0; merge_idx < merge_faces.size(); ++merge_idx) { + int outer_edge_idx[2]; + outer_edge_idx[0] = merge_faces[merge_idx].vertex_idx[(merge_faces_inner_vertex_idx[merge_idx] + 1) % 3]; + outer_edge_idx[1] = merge_faces[merge_idx].vertex_idx[(merge_faces_inner_vertex_idx[merge_idx] + 2) % 3]; - switch (p_operation) { + // Skip flattened faces. + if (outer_edge_idx[0] == p_segment_indices[closest_idx] || + outer_edge_idx[1] == p_segment_indices[closest_idx]) { + continue; + } - case OPERATION_UNION: { + //Don't create degenerate triangles. + Vector2 edge1[2] = { + vertices[outer_edge_idx[0]].point, + vertices[p_segment_indices[closest_idx]].point + }; + Vector2 edge2[2] = { + vertices[outer_edge_idx[1]].point, + vertices[p_segment_indices[closest_idx]].point + }; + if (are_segements_parallel(edge1, edge2, vertex_snap2)) { + degenerate_points.push_back(outer_edge_idx[0]); + degenerate_points.push_back(outer_edge_idx[1]); + continue; + } - int outside_count = 0; + // Create new faces. + Face2D new_face; + new_face.vertex_idx[0] = p_segment_indices[closest_idx]; + new_face.vertex_idx[1] = outer_edge_idx[0]; + new_face.vertex_idx[2] = outer_edge_idx[1]; + faces.push_back(new_face); + } - for (int i = 0; i < mesh_merge.faces.size(); i++) { - if (mesh_merge.faces[i].inside) + // Delete the old faces in reverse index order. + merge_faces_idx.sort(); + merge_faces_idx.invert(); + for (int i = 0; i < merge_faces_idx.size(); ++i) { + faces.remove(merge_faces_idx[i]); + } + + if (degenerate_points.size() == 0) { + continue; + } + + // Split faces using degenerate points. + for (int face_idx = 0; face_idx < faces.size(); ++face_idx) { + Face2D face = faces[face_idx]; + Vertex2D face_vertices[3] = { + vertices[face.vertex_idx[0]], + vertices[face.vertex_idx[1]], + vertices[face.vertex_idx[2]] + }; + Vector2 face_points[3] = { + face_vertices[0].point, + face_vertices[1].point, + face_vertices[2].point + }; + + for (int point_idx = 0; point_idx < degenerate_points.size(); ++point_idx) { + int degenerate_idx = degenerate_points[point_idx]; + Vector2 point_2D = vertices[degenerate_idx].point; + + // Check if point is existing face vertex. + bool existing = false; + for (int i = 0; i < 3; ++i) { + if ((point_2D - face_vertices[i].point).length_squared() < vertex_snap2) { + existing = true; + break; + } + } + if (existing) { continue; + } - outside_count++; + // Check if point is on an each edge. + for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) { + Vector2 edge_points[2] = { + face_points[face_edge_idx], + face_points[(face_edge_idx + 1) % 3] + }; + Vector2 closest_point = Geometry::get_closest_point_to_segment_2d(point_2D, edge_points); + + if ((closest_point - point_2D).length_squared() < vertex_snap2) { + int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3]; + + // If new vertex snaps to degenerate vertex, just delete this face. + if (degenerate_idx == opposite_vertex_idx) { + faces.remove(face_idx); + // Update index. + --face_idx; + break; + } + + // Create two new faces around the new edge and remove this face. + // The new edge is the last edge. + Face2D left_face; + left_face.vertex_idx[0] = degenerate_idx; + left_face.vertex_idx[1] = face.vertex_idx[(face_edge_idx + 1) % 3]; + left_face.vertex_idx[2] = opposite_vertex_idx; + Face2D right_face; + right_face.vertex_idx[0] = opposite_vertex_idx; + right_face.vertex_idx[1] = face.vertex_idx[face_edge_idx]; + right_face.vertex_idx[2] = degenerate_idx; + faces.remove(face_idx); + faces.insert(face_idx, right_face); + faces.insert(face_idx, left_face); + + // Don't check against the new faces. + ++face_idx; + + // No need to check other edges. + break; + } + } } + } + } +} - result.faces.resize(outside_count); +void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_segment_points[2], Vector<int> &r_segment_indices) { + // For each face. + for (int face_idx = 0; face_idx < faces.size(); ++face_idx) { + Face2D face = faces[face_idx]; + Vertex2D face_vertices[3] = { + vertices[face.vertex_idx[0]], + vertices[face.vertex_idx[1]], + vertices[face.vertex_idx[2]] + }; + + // Check each edge. + for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) { + Vector2 edge_points[2] = { + face_vertices[face_edge_idx].point, + face_vertices[(face_edge_idx + 1) % 3].point + }; + Vector2 edge_uvs[2] = { + face_vertices[face_edge_idx].uv, + face_vertices[(face_edge_idx + 1) % 3].uv + }; + Vector2 intersection_point; + + // First check if the ends of the segment are on the edge. + bool on_edge = false; + for (int edge_point_idx = 0; edge_point_idx < 2; ++edge_point_idx) { + intersection_point = Geometry::get_closest_point_to_segment_2d(p_segment_points[edge_point_idx], edge_points); + if ((intersection_point - p_segment_points[edge_point_idx]).length_squared() < vertex_snap2) { + on_edge = true; + break; + } + } - outside_count = 0; + // Else check if the segment intersects the edge. + if (on_edge || Geometry::segment_intersects_segment_2d(p_segment_points[0], p_segment_points[1], edge_points[0], edge_points[1], &intersection_point)) { + // Check if intersection point is an edge point. + if ((intersection_point - edge_points[0]).length_squared() < vertex_snap2 || + (intersection_point - edge_points[1]).length_squared() < vertex_snap2) { + continue; + } - for (int i = 0; i < mesh_merge.faces.size(); i++) { - if (mesh_merge.faces[i].inside) + // Check if edge exists, by checking if the intersecting segment is parallel to the edge. + if (are_segements_parallel(p_segment_points, edge_points, vertex_snap2)) { continue; - for (int j = 0; j < 3; j++) { - result.faces.write[outside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; - result.faces.write[outside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; } - result.faces.write[outside_count].smooth = mesh_merge.faces[i].smooth; - result.faces.write[outside_count].invert = mesh_merge.faces[i].invert; - result.faces.write[outside_count].material = mesh_merge.faces[i].material_idx; - outside_count++; + // Add the intersection point as a new vertex. + Vertex2D new_vertex; + new_vertex.point = intersection_point; + new_vertex.uv = interpolate_segment_uv(edge_points, edge_uvs, intersection_point); + int new_vertex_idx = _add_vertex(new_vertex); + int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3]; + _add_vertex_idx_sorted(r_segment_indices, new_vertex_idx); + + // If new vertex snaps to opposite vertex, just delete this face. + if (new_vertex_idx == opposite_vertex_idx) { + faces.remove(face_idx); + // Update index. + --face_idx; + break; + } + + // Don't create degenerate triangles. + Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] }; + Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] }; + Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point }; + if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) && + are_segements_parallel(split_edge2, new_edge, vertex_snap2)) { + break; + } + + // If opposite point is on the segemnt, add its index to segment indices too. + Vector2 closest_point = Geometry::get_closest_point_to_segment_2d(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); + } + + // Create two new faces around the new edge and remove this face. + // The new edge is the last edge. + Face2D left_face; + left_face.vertex_idx[0] = new_vertex_idx; + left_face.vertex_idx[1] = face.vertex_idx[(face_edge_idx + 1) % 3]; + left_face.vertex_idx[2] = opposite_vertex_idx; + Face2D right_face; + right_face.vertex_idx[0] = opposite_vertex_idx; + right_face.vertex_idx[1] = face.vertex_idx[face_edge_idx]; + right_face.vertex_idx[2] = new_vertex_idx; + faces.remove(face_idx); + faces.insert(face_idx, right_face); + faces.insert(face_idx, left_face); + + // Check against the new faces. + --face_idx; + break; } + } + } +} - result._regen_face_aabbs(); +int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) { + int new_vertex_idx = -1; + + for (int face_idx = 0; face_idx < faces.size(); ++face_idx) { + Face2D face = faces[face_idx]; + Vertex2D face_vertices[3] = { + vertices[face.vertex_idx[0]], + vertices[face.vertex_idx[1]], + vertices[face.vertex_idx[2]] + }; + Vector2 points[3] = { + face_vertices[0].point, + face_vertices[1].point, + face_vertices[2].point + }; + Vector2 uvs[3] = { + face_vertices[0].uv, + face_vertices[1].uv, + face_vertices[2].uv + }; + + // Check if point is existing face vertex. + for (int i = 0; i < 3; ++i) { + if ((p_point - face_vertices[i].point).length_squared() < vertex_snap2) { + return face.vertex_idx[i]; + } + } - } break; - case OPERATION_INTERSECTION: { + // Check if point is on an each edge. + bool on_edge = false; + for (int face_edge_idx = 0; face_edge_idx < 3; ++face_edge_idx) { + Vector2 edge_points[2] = { + points[face_edge_idx], + points[(face_edge_idx + 1) % 3] + }; + Vector2 edge_uvs[2] = { + uvs[face_edge_idx], + uvs[(face_edge_idx + 1) % 3] + }; + + Vector2 closest_point = Geometry::get_closest_point_to_segment_2d(p_point, edge_points); + if ((closest_point - p_point).length_squared() < vertex_snap2) { + on_edge = true; + + // Add the point as a new vertex. + Vertex2D new_vertex; + new_vertex.point = p_point; + new_vertex.uv = interpolate_segment_uv(edge_points, edge_uvs, p_point); + new_vertex_idx = _add_vertex(new_vertex); + int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3]; + + // If new vertex snaps to opposite vertex, just delete this face. + if (new_vertex_idx == opposite_vertex_idx) { + faces.remove(face_idx); + // Update index. + --face_idx; + break; + } - int inside_count = 0; + // Don't create degenerate triangles. + Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] }; + Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] }; + Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point }; + if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) && + are_segements_parallel(split_edge2, new_edge, vertex_snap2)) { + break; + } - for (int i = 0; i < mesh_merge.faces.size(); i++) { - if (!mesh_merge.faces[i].inside) + // Create two new faces around the new edge and remove this face. + // The new edge is the last edge. + Face2D left_face; + left_face.vertex_idx[0] = new_vertex_idx; + left_face.vertex_idx[1] = face.vertex_idx[(face_edge_idx + 1) % 3]; + left_face.vertex_idx[2] = opposite_vertex_idx; + Face2D right_face; + right_face.vertex_idx[0] = opposite_vertex_idx; + right_face.vertex_idx[1] = face.vertex_idx[face_edge_idx]; + right_face.vertex_idx[2] = new_vertex_idx; + faces.remove(face_idx); + faces.insert(face_idx, right_face); + faces.insert(face_idx, left_face); + + // Don't check against the new faces. + ++face_idx; + + // No need to check other edges. + break; + } + } + + // If not on an edge, check if the point is inside the face. + if (!on_edge && Geometry::is_point_in_triangle(p_point, face_vertices[0].point, face_vertices[1].point, face_vertices[2].point)) { + // Add the point as a new vertex. + Vertex2D new_vertex; + new_vertex.point = p_point; + new_vertex.uv = interpolate_triangle_uv(points, uvs, p_point); + new_vertex_idx = _add_vertex(new_vertex); + + // Create three new faces around this point and remove this face. + // The new vertex is the last vertex. + for (int i = 0; i < 3; ++i) { + // Don't create degenerate triangles. + Vector2 edge[2] = { points[i], points[(i + 1) % 3] }; + Vector2 new_edge1[2] = { vertices[new_vertex_idx].point, points[i] }; + Vector2 new_edge2[2] = { vertices[new_vertex_idx].point, points[(i + 1) % 3] }; + if (are_segements_parallel(edge, new_edge1, vertex_snap2) && + are_segements_parallel(edge, new_edge2, vertex_snap2)) { continue; + } - inside_count++; + Face2D new_face; + new_face.vertex_idx[0] = face.vertex_idx[i]; + new_face.vertex_idx[1] = face.vertex_idx[(i + 1) % 3]; + new_face.vertex_idx[2] = new_vertex_idx; + faces.push_back(new_face); } + faces.remove(face_idx); - result.faces.resize(inside_count); + // No need to check other faces. + break; + } + } - inside_count = 0; + return new_vertex_idx; +} - for (int i = 0; i < mesh_merge.faces.size(); i++) { - if (!mesh_merge.faces[i].inside) - continue; - for (int j = 0; j < 3; j++) { - result.faces.write[inside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; - result.faces.write[inside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; - } +void CSGBrushOperation::Build2DFaces::insert(const CSGBrush &p_brush, int p_face_idx) { + // Find edge points that cross the plane and face points that are in the plane. + // Map those points to 2D. + // Create new faces from those points. - result.faces.write[inside_count].smooth = mesh_merge.faces[i].smooth; - result.faces.write[inside_count].invert = mesh_merge.faces[i].invert; - result.faces.write[inside_count].material = mesh_merge.faces[i].material_idx; - inside_count++; + Vector2 points_2D[3]; + int points_count = 0; + + for (int i = 0; i < 3; i++) { + Vector3 point_3D = p_brush.faces[p_face_idx].vertices[i]; + + if (plane.has_point(point_3D)) { + // Point is in the plane, add it. + Vector3 point_2D = plane.project(point_3D); + point_2D = to_2D.xform(point_2D); + points_2D[points_count++] = Vector2(point_2D.x, point_2D.y); + + } else { + Vector3 next_point_3D = p_brush.faces[p_face_idx].vertices[(i + 1) % 3]; + + if (plane.has_point(next_point_3D)) { + continue; // Next point is in plane, it will be added separately. + } + if (plane.is_point_over(point_3D) == plane.is_point_over(next_point_3D)) { + continue; // Both points on the same side of the plane, ignore. } - result._regen_face_aabbs(); + // Edge crosses the plane, find and add the intersection point. + Vector3 point_2D; + if (plane.intersects_segment(point_3D, next_point_3D, &point_2D)) { + point_2D = to_2D.xform(point_2D); + points_2D[points_count++] = Vector2(point_2D.x, point_2D.y); + } + } + } - } break; - case OPERATION_SUBSTRACTION: { + Vector<int> segment_indices; + Vector2 segment[2]; + int inserted_index[3] = { -1, -1, -1 }; - int face_count = 0; + // Insert points. + for (int i = 0; i < points_count; ++i) { + inserted_index[i] = _insert_point(points_2D[i]); + } - for (int i = 0; i < mesh_merge.faces.size(); i++) { - if (mesh_merge.faces[i].from_b && !mesh_merge.faces[i].inside) - continue; - if (!mesh_merge.faces[i].from_b && mesh_merge.faces[i].inside) - continue; + if (points_count == 2) { + // Insert a single segment. + segment[0] = points_2D[0]; + segment[1] = points_2D[1]; + _find_edge_intersections(segment, segment_indices); + for (int i = 0; i < 2; ++i) { + _add_vertex_idx_sorted(segment_indices, inserted_index[i]); + } + _merge_faces(segment_indices); + } - face_count++; + if (points_count == 3) { + // Insert three segments. + for (int edge_idx = 0; edge_idx < 3; ++edge_idx) { + segment[0] = points_2D[edge_idx]; + segment[1] = points_2D[(edge_idx + 1) % 3]; + _find_edge_intersections(segment, segment_indices); + for (int i = 0; i < 2; ++i) { + _add_vertex_idx_sorted(segment_indices, inserted_index[(edge_idx + i) % 3]); } + _merge_faces(segment_indices); + segment_indices.clear(); + } + } +} - result.faces.resize(face_count); +void CSGBrushOperation::Build2DFaces::addFacesToMesh(MeshMerge &r_mesh_merge, bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) { + for (int face_idx = 0; face_idx < faces.size(); ++face_idx) { + Face2D face = faces[face_idx]; + Vertex2D fv[3] = { + vertices[face.vertex_idx[0]], + vertices[face.vertex_idx[1]], + vertices[face.vertex_idx[2]] + }; + + // Convert 2D vertex points to 3D. + Vector3 points_3D[3]; + Vector2 uvs[3]; + for (int i = 0; i < 3; ++i) { + Vector3 point_2D(fv[i].point.x, fv[i].point.y, 0); + points_3D[i] = to_3D.xform(point_2D); + uvs[i] = fv[i].uv; + } - face_count = 0; + r_mesh_merge.add_face(points_3D, uvs, p_smooth, p_invert, p_material, p_from_b); + } +} - for (int i = 0; i < mesh_merge.faces.size(); i++) { +CSGBrushOperation::Build2DFaces::Build2DFaces(const CSGBrush &p_brush, int p_face_idx, float p_vertex_snap2) : + vertex_snap2(p_vertex_snap2 * p_vertex_snap2) { + // Convert 3D vertex points to 2D. + Vector3 points_3D[3] = { + p_brush.faces[p_face_idx].vertices[0], + p_brush.faces[p_face_idx].vertices[1], + p_brush.faces[p_face_idx].vertices[2], + }; - if (mesh_merge.faces[i].from_b && !mesh_merge.faces[i].inside) - continue; - if (!mesh_merge.faces[i].from_b && mesh_merge.faces[i].inside) - continue; + plane = Plane(points_3D[0], points_3D[1], points_3D[2]); + to_3D.origin = points_3D[0]; + to_3D.basis.set_axis(2, plane.normal); + to_3D.basis.set_axis(0, (points_3D[1] - points_3D[2]).normalized()); + to_3D.basis.set_axis(1, to_3D.basis.get_axis(0).cross(to_3D.basis.get_axis(2)).normalized()); + to_2D = to_3D.affine_inverse(); - for (int j = 0; j < 3; j++) { - result.faces.write[face_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; - result.faces.write[face_count].uvs[j] = mesh_merge.faces[i].uvs[j]; + Face2D face; + for (int i = 0; i < 3; i++) { + Vertex2D vertex; + Vector3 point_2D = to_2D.xform(points_3D[i]); + vertex.point.x = point_2D.x; + vertex.point.y = point_2D.y; + vertex.uv = p_brush.faces[p_face_idx].uvs[i]; + vertices.push_back(vertex); + face.vertex_idx[i] = i; + } + faces.push_back(face); +} + +void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face_idx_a, const CSGBrush &p_brush_b, const int p_face_idx_b, Build2DFaceCollection &p_collection, float p_vertex_snap) { + Vector3 vertices_a[3] = { + p_brush_a.faces[p_face_idx_a].vertices[0], + p_brush_a.faces[p_face_idx_a].vertices[1], + p_brush_a.faces[p_face_idx_a].vertices[2], + }; + + Vector3 vertices_b[3] = { + p_brush_b.faces[p_face_idx_b].vertices[0], + p_brush_b.faces[p_face_idx_b].vertices[1], + p_brush_b.faces[p_face_idx_b].vertices[2], + }; + + // Don't use degenerate faces. + bool has_degenerate = false; + if (is_snapable(vertices_a[0], vertices_a[1], p_vertex_snap) || + is_snapable(vertices_a[0], vertices_a[2], p_vertex_snap) || + is_snapable(vertices_a[1], vertices_a[2], p_vertex_snap)) { + p_collection.build2DFacesA[p_face_idx_a] = Build2DFaces(); + has_degenerate = true; + } + + if (is_snapable(vertices_b[0], vertices_b[1], p_vertex_snap) || + is_snapable(vertices_b[0], vertices_b[2], p_vertex_snap) || + is_snapable(vertices_b[1], vertices_b[2], p_vertex_snap)) { + p_collection.build2DFacesB[p_face_idx_b] = Build2DFaces(); + has_degenerate = true; + } + if (has_degenerate) { + return; + } + + // Ensure B has points either side of or in the plane of A. + int in_plane_count = 0, over_count = 0, under_count = 0; + Plane plane_a(vertices_a[0], vertices_a[1], vertices_a[2]); + ERR_FAIL_COND_MSG(plane_a.normal == Vector3(), "Couldn't form plane from Brush A face."); + + for (int i = 0; i < 3; i++) { + if (plane_a.has_point(vertices_b[i])) { + in_plane_count++; + } else if (plane_a.is_point_over(vertices_b[i])) { + over_count++; + } else { + under_count++; + } + } + // If all points under or over the plane, there is no intesection. + if (over_count == 3 || under_count == 3) { + return; + } + + // Ensure A has points either side of or in the plane of B. + in_plane_count = 0; + over_count = 0; + under_count = 0; + Plane plane_b(vertices_b[0], vertices_b[1], vertices_b[2]); + ERR_FAIL_COND_MSG(plane_b.normal == Vector3(), "Couldn't form plane from Brush B face."); + + for (int i = 0; i < 3; i++) { + if (plane_b.has_point(vertices_a[i])) { + in_plane_count++; + } else if (plane_b.is_point_over(vertices_a[i])) { + over_count++; + } else { + under_count++; + } + } + // If all points under or over the plane, there is no intesection. + if (over_count == 3 || under_count == 3) { + return; + } + + // Check for intersection using the SAT theorem. + { + // Edge pair cross product combinations. + for (int i = 0; i < 3; i++) { + Vector3 axis_a = (vertices_a[i] - vertices_a[(i + 1) % 3]).normalized(); + + for (int j = 0; j < 3; j++) { + Vector3 axis_b = (vertices_b[j] - vertices_b[(j + 1) % 3]).normalized(); + + Vector3 sep_axis = axis_a.cross(axis_b); + if (sep_axis == Vector3()) { + continue; //colineal } + sep_axis.normalize(); - if (mesh_merge.faces[i].from_b) { - //invert facing of insides of B - SWAP(result.faces.write[face_count].vertices[1], result.faces.write[face_count].vertices[2]); - SWAP(result.faces.write[face_count].uvs[1], result.faces.write[face_count].uvs[2]); + real_t min_a = 1e20, max_a = -1e20; + real_t min_b = 1e20, max_b = -1e20; + + for (int k = 0; k < 3; k++) { + real_t d = sep_axis.dot(vertices_a[k]); + min_a = MIN(min_a, d); + max_a = MAX(max_a, d); + d = sep_axis.dot(vertices_b[k]); + min_b = MIN(min_b, d); + max_b = MAX(max_b, d); } - result.faces.write[face_count].smooth = mesh_merge.faces[i].smooth; - result.faces.write[face_count].invert = mesh_merge.faces[i].invert; - result.faces.write[face_count].material = mesh_merge.faces[i].material_idx; - face_count++; - } + min_b -= (max_a - min_a) * 0.5; + max_b += (max_a - min_a) * 0.5; - result._regen_face_aabbs(); + real_t dmin = min_b - (min_a + max_a) * 0.5; + real_t dmax = max_b - (min_a + max_a) * 0.5; - } break; + if (dmin > CMP_EPSILON || dmax < -CMP_EPSILON) { + return; // Does not contain zero, so they don't overlap. + } + } + } } - //updatelist of materials - result.materials.resize(mesh_merge.materials.size()); - for (const Map<Ref<Material>, int>::Element *E = mesh_merge.materials.front(); E; E = E->next()) { - result.materials.write[E->get()] = E->key(); + // If we're still here, the faces probably intersect, so add new faces. + if (!p_collection.build2DFacesA.has(p_face_idx_a)) { + p_collection.build2DFacesA[p_face_idx_a] = Build2DFaces(p_brush_a, p_face_idx_a, p_vertex_snap); + } + p_collection.build2DFacesA[p_face_idx_a].insert(p_brush_b, p_face_idx_b); + + if (!p_collection.build2DFacesB.has(p_face_idx_b)) { + p_collection.build2DFacesB[p_face_idx_b] = Build2DFaces(p_brush_b, p_face_idx_b, p_vertex_snap); } + p_collection.build2DFacesB[p_face_idx_b].insert(p_brush_a, p_face_idx_a); } diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 4fa1a945cc..34ee239c17 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,20 +31,20 @@ #ifndef CSG_H #define CSG_H +#include "core/list.h" #include "core/map.h" #include "core/math/aabb.h" #include "core/math/plane.h" -#include "core/math/rect2.h" #include "core/math/transform.h" +#include "core/math/vector2.h" #include "core/math/vector3.h" #include "core/oa_hash_map.h" -#include "core/pool_vector.h" +#include "core/reference.h" +#include "core/vector.h" #include "scene/resources/material.h" struct CSGBrush { - struct Face { - Vector3 vertices[3]; Vector2 uvs[3]; AABB aabb; @@ -54,28 +54,36 @@ struct CSGBrush { }; Vector<Face> faces; - Vector<Ref<Material> > materials; + Vector<Ref<Material>> materials; - void _regen_face_aabbs(); - //create a brush from faces - void build_from_faces(const PoolVector<Vector3> &p_vertices, const PoolVector<Vector2> &p_uvs, const PoolVector<bool> &p_smooth, const PoolVector<Ref<Material> > &p_materials, const PoolVector<bool> &p_invert_faces); - void copy_from(const CSGBrush &p_brush, const Transform &p_xform); + inline void _regen_face_aabbs(); - void clear(); + // 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); }; struct CSGBrushOperation { - enum Operation { OPERATION_UNION, OPERATION_INTERSECTION, OPERATION_SUBSTRACTION, - }; + void merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap); + struct MeshMerge { + struct Face { + bool from_b; + bool inside; + int points[3]; + Vector2 uvs[3]; + bool smooth; + bool invert; + int material_idx; + }; - struct BVH { + struct FaceBVH { int face; int left; int right; @@ -84,32 +92,23 @@ struct CSGBrushOperation { AABB aabb; }; - struct BVHCmpX { - - bool operator()(const BVH *p_left, const BVH *p_right) const { - + struct FaceBVHCmpX { + _FORCE_INLINE_ bool operator()(const FaceBVH *p_left, const FaceBVH *p_right) const { return p_left->center.x < p_right->center.x; } }; - struct BVHCmpY { - - bool operator()(const BVH *p_left, const BVH *p_right) const { - + struct FaceBVHCmpY { + _FORCE_INLINE_ bool operator()(const FaceBVH *p_left, const FaceBVH *p_right) const { return p_left->center.y < p_right->center.y; } }; - struct BVHCmpZ { - - bool operator()(const BVH *p_left, const BVH *p_right) const { - + struct FaceBVHCmpZ { + _FORCE_INLINE_ bool operator()(const FaceBVH *p_left, const FaceBVH *p_right) const { return p_left->center.z < p_right->center.z; } }; - int _bvh_count_intersections(BVH *bvhptr, int p_max_depth, int p_bvh_first, const Vector3 &p_begin, const Vector3 &p_end, int p_exclude) const; - int _create_bvh(BVH *p_bvh, BVH **p_bb, int p_from, int p_size, int p_depth, int &max_depth, int &max_alloc); - struct VertexKey { int32_t x, y, z; _FORCE_INLINE_ bool operator<(const VertexKey &p_key) const { @@ -138,99 +137,58 @@ struct CSGBrushOperation { } }; - OAHashMap<VertexKey, int, VertexKeyHash> snap_cache; - Vector<Vector3> points; - - struct Face { - bool from_b; - bool inside; - int points[3]; - Vector2 uvs[3]; - bool smooth; - bool invert; - int material_idx; - }; - Vector<Face> faces; - Map<Ref<Material>, int> materials; - Map<Vector3, int> vertex_map; - void add_face(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector2 &p_uv_a, const Vector2 &p_uv_b, const Vector2 &p_uv_c, bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b); - // void add_face(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, bool p_from_b); - + OAHashMap<VertexKey, int, VertexKeyHash> snap_cache; float vertex_snap; - void mark_inside_faces(); - }; - struct BuildPoly { + inline void _add_distance(List<real_t> &r_intersectionsA, List<real_t> &r_intersectionsB, bool p_from_B, real_t p_distance) const; + inline bool _bvh_inside(FaceBVH *facebvhptr, int p_max_depth, int p_bvh_first, int p_face_idx) const; + inline int _create_bvh(FaceBVH *facebvhptr, FaceBVH **facebvhptrptr, int p_from, int p_size, int p_depth, int &r_max_depth, int &r_max_alloc); - Plane plane; - Transform to_poly; - Transform to_world; - int face_index; + void add_face(const Vector3 p_points[3], const Vector2 p_uvs[3], bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b); + void mark_inside_faces(); + }; - struct Point { + struct Build2DFaces { + struct Vertex2D { Vector2 point; Vector2 uv; }; - Vector<Point> points; - - struct Edge { - bool outer; - int points[2]; - Edge() { - outer = false; - } + struct Face2D { + int vertex_idx[3]; }; - Vector<Edge> edges; - Ref<Material> material; - bool smooth; - bool invert; - - int base_edges; //edges from original triangle, even if split - - void _clip_segment(const CSGBrush *p_brush, int p_face, const Vector2 *segment, MeshMerge &mesh_merge, bool p_for_B); - - void create(const CSGBrush *p_brush, int p_face, MeshMerge &mesh_merge, bool p_for_B); - void clip(const CSGBrush *p_brush, int p_face, MeshMerge &mesh_merge, bool p_for_B); - }; - - struct PolyPoints { - - Vector<int> points; - - Vector<Vector<int> > holes; - }; - - struct EdgeSort { - int edge; - int prev_point; - int edge_point; - float angle; - bool operator<(const EdgeSort &p_edge) const { return angle < p_edge.angle; } + Vector<Vertex2D> vertices; + Vector<Face2D> faces; + Plane plane; + Transform to_2D; + Transform to_3D; + float vertex_snap2; + + inline int _get_point_idx(const Vector2 &p_point); + inline int _add_vertex(const Vertex2D &p_vertex); + inline void _add_vertex_idx_sorted(Vector<int> &r_vertex_indices, int p_new_vertex_index); + inline void _merge_faces(const Vector<int> &p_segment_indices); + inline void _find_edge_intersections(const Vector2 p_segment_points[2], Vector<int> &r_segment_indices); + inline int _insert_point(const Vector2 &p_point); + + void insert(const CSGBrush &p_brush, int p_brush_face); + void addFacesToMesh(MeshMerge &r_mesh_merge, bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b); + + Build2DFaces() {} + Build2DFaces(const CSGBrush &p_brush, int p_brush_face, float p_vertex_snap2); }; - struct CallbackData { - const CSGBrush *A; - const CSGBrush *B; - int face_a; - CSGBrushOperation *self; - Map<int, BuildPoly> build_polys_A; - Map<int, BuildPoly> build_polys_B; + struct Build2DFaceCollection { + Map<int, Build2DFaces> build2DFacesA; + Map<int, Build2DFaces> build2DFacesB; }; - void _add_poly_points(const BuildPoly &p_poly, int p_edge, int p_from_point, int p_to_point, const Vector<Vector<int> > &vertex_process, Vector<bool> &edge_process, Vector<PolyPoints> &r_poly); - void _add_poly_outline(const BuildPoly &p_poly, int p_from_point, int p_to_point, const Vector<Vector<int> > &vertex_process, Vector<int> &r_outline); - void _merge_poly(MeshMerge &mesh, int p_face_idx, const BuildPoly &p_poly, bool p_from_b); - - void _collision_callback(const CSGBrush *A, int p_face_a, Map<int, BuildPoly> &build_polys_a, const CSGBrush *B, int p_face_b, Map<int, BuildPoly> &build_polys_b, MeshMerge &mesh_merge); - - static void _collision_callbacks(void *ud, int p_face_b); - void merge_brushes(Operation p_operation, const CSGBrush &p_A, const CSGBrush &p_B, CSGBrush &result, float p_snap = 0.001); + void update_faces(const CSGBrush &p_brush_a, const int p_face_idx_a, const CSGBrush &p_brush_b, const int p_face_idx_b, Build2DFaceCollection &p_collection, float p_vertex_snap); }; #endif // CSG_H diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 0d26943af6..9fa7dc1340 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,8 +32,7 @@ /////////// -CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() { - +CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15)); create_material("shape_union_material", gizmo_color); create_material("shape_union_solid_material", gizmo_color); @@ -49,70 +48,64 @@ CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() { create_handle_material("handles"); } -String CSGShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { - - CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); - - if (Object::cast_to<CSGSphere>(cs)) { +String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); + if (Object::cast_to<CSGSphere3D>(cs)) { return "Radius"; } - if (Object::cast_to<CSGBox>(cs)) { - + if (Object::cast_to<CSGBox3D>(cs)) { static const char *hname[3] = { "Width", "Height", "Depth" }; return hname[p_idx]; } - if (Object::cast_to<CSGCylinder>(cs)) { - + if (Object::cast_to<CSGCylinder3D>(cs)) { return p_idx == 0 ? "Radius" : "Height"; } - if (Object::cast_to<CSGTorus>(cs)) { - + if (Object::cast_to<CSGTorus3D>(cs)) { return p_idx == 0 ? "InnerRadius" : "OuterRadius"; } return ""; } -Variant CSGShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { - CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); +Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); - if (Object::cast_to<CSGSphere>(cs)) { - - CSGSphere *s = Object::cast_to<CSGSphere>(cs); + if (Object::cast_to<CSGSphere3D>(cs)) { + CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs); return s->get_radius(); } - if (Object::cast_to<CSGBox>(cs)) { - - CSGBox *s = Object::cast_to<CSGBox>(cs); + if (Object::cast_to<CSGBox3D>(cs)) { + CSGBox3D *s = Object::cast_to<CSGBox3D>(cs); switch (p_idx) { - case 0: return s->get_width(); - case 1: return s->get_height(); - case 2: return s->get_depth(); + case 0: + return s->get_width(); + case 1: + return s->get_height(); + case 2: + return s->get_depth(); } } - if (Object::cast_to<CSGCylinder>(cs)) { - - CSGCylinder *s = Object::cast_to<CSGCylinder>(cs); + if (Object::cast_to<CSGCylinder3D>(cs)) { + CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); return p_idx == 0 ? s->get_radius() : s->get_height(); } - if (Object::cast_to<CSGTorus>(cs)) { - - CSGTorus *s = Object::cast_to<CSGTorus>(cs); + 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 Variant(); } -void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { - CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); +void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); Transform gt = cs->get_global_transform(); //gt.orthonormalize(); @@ -123,127 +116,147 @@ void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_i Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - if (Object::cast_to<CSGSphere>(cs)) { - - CSGSphere *s = Object::cast_to<CSGSphere>(cs); + if (Object::cast_to<CSGSphere3D>(cs)) { + CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs); Vector3 ra, rb; Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb); float d = ra.x; - if (SpatialEditor::get_singleton()->is_snap_enabled()) { - d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap()); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap()); } - if (d < 0.001) + if (d < 0.001) { d = 0.001; + } s->set_radius(d); } - if (Object::cast_to<CSGBox>(cs)) { - - CSGBox *s = Object::cast_to<CSGBox>(cs); + if (Object::cast_to<CSGBox3D>(cs)) { + CSGBox3D *s = Object::cast_to<CSGBox3D>(cs); Vector3 axis; axis[p_idx] = 1.0; Vector3 ra, rb; Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); float d = ra[p_idx]; - if (SpatialEditor::get_singleton()->is_snap_enabled()) { - d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap()); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap()); } - if (d < 0.001) + if (d < 0.001) { d = 0.001; + } switch (p_idx) { - case 0: s->set_width(d * 2); break; - case 1: s->set_height(d * 2); break; - case 2: s->set_depth(d * 2); break; + case 0: + s->set_width(d * 2); + break; + case 1: + s->set_height(d * 2); + break; + case 2: + s->set_depth(d * 2); + break; } } - if (Object::cast_to<CSGCylinder>(cs)) { - - CSGCylinder *s = Object::cast_to<CSGCylinder>(cs); + if (Object::cast_to<CSGCylinder3D>(cs)) { + CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); Vector3 axis; axis[p_idx == 0 ? 0 : 1] = 1.0; Vector3 ra, rb; Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); float d = axis.dot(ra); - if (SpatialEditor::get_singleton()->is_snap_enabled()) { - d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap()); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap()); } - if (d < 0.001) + if (d < 0.001) { d = 0.001; + } - if (p_idx == 0) + if (p_idx == 0) { s->set_radius(d); - else if (p_idx == 1) + } else if (p_idx == 1) { s->set_height(d * 2.0); + } } - if (Object::cast_to<CSGTorus>(cs)) { - - CSGTorus *s = Object::cast_to<CSGTorus>(cs); + if (Object::cast_to<CSGTorus3D>(cs)) { + CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs); Vector3 axis; axis[0] = 1.0; Vector3 ra, rb; Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb); float d = axis.dot(ra); - if (SpatialEditor::get_singleton()->is_snap_enabled()) { - d = Math::stepify(d, SpatialEditor::get_singleton()->get_translate_snap()); + if (Node3DEditor::get_singleton()->is_snap_enabled()) { + d = Math::stepify(d, Node3DEditor::get_singleton()->get_translate_snap()); } - if (d < 0.001) + if (d < 0.001) { d = 0.001; + } - if (p_idx == 0) + if (p_idx == 0) { s->set_inner_radius(d); - else if (p_idx == 1) + } else if (p_idx == 1) { s->set_outer_radius(d); + } } } -void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { - CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); +void CSGShape3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); - if (Object::cast_to<CSGSphere>(cs)) { - CSGSphere *s = Object::cast_to<CSGSphere>(cs); + if (Object::cast_to<CSGSphere3D>(cs)) { + CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs); if (p_cancel) { s->set_radius(p_restore); return; } - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); ur->add_undo_method(s, "set_radius", p_restore); ur->commit_action(); } - if (Object::cast_to<CSGBox>(cs)) { - CSGBox *s = Object::cast_to<CSGBox>(cs); + if (Object::cast_to<CSGBox3D>(cs)) { + CSGBox3D *s = Object::cast_to<CSGBox3D>(cs); if (p_cancel) { switch (p_idx) { - case 0: s->set_width(p_restore); break; - case 1: s->set_height(p_restore); break; - case 2: s->set_depth(p_restore); break; + case 0: + s->set_width(p_restore); + break; + case 1: + s->set_height(p_restore); + break; + case 2: + s->set_depth(p_restore); + break; } return; } - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); ur->create_action(TTR("Change Box Shape Extents")); static const char *method[3] = { "set_width", "set_height", "set_depth" }; float current = 0; switch (p_idx) { - case 0: current = s->get_width(); break; - case 1: current = s->get_height(); break; - case 2: current = s->get_depth(); break; + case 0: + current = s->get_width(); + break; + case 1: + current = s->get_height(); + break; + case 2: + current = s->get_depth(); + break; } ur->add_do_method(s, method[p_idx], current); @@ -251,17 +264,18 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int ur->commit_action(); } - if (Object::cast_to<CSGCylinder>(cs)) { - CSGCylinder *s = Object::cast_to<CSGCylinder>(cs); + if (Object::cast_to<CSGCylinder3D>(cs)) { + CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); if (p_cancel) { - if (p_idx == 0) + if (p_idx == 0) { s->set_radius(p_restore); - else + } else { s->set_height(p_restore); + } return; } - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); if (p_idx == 0) { ur->create_action(TTR("Change Cylinder Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); @@ -275,17 +289,18 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int ur->commit_action(); } - if (Object::cast_to<CSGTorus>(cs)) { - CSGTorus *s = Object::cast_to<CSGTorus>(cs); + if (Object::cast_to<CSGTorus3D>(cs)) { + CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs); if (p_cancel) { - if (p_idx == 0) + if (p_idx == 0) { s->set_inner_radius(p_restore); - else + } else { s->set_outer_radius(p_restore); + } return; } - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); if (p_idx == 0) { ur->create_action(TTR("Change Torus Inner Radius")); ur->add_do_method(s, "set_inner_radius", s->get_inner_radius()); @@ -299,49 +314,49 @@ void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int ur->commit_action(); } } -bool CSGShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { - return Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial); + +bool CSGShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to<CSGSphere3D>(p_spatial) || Object::cast_to<CSGBox3D>(p_spatial) || Object::cast_to<CSGCylinder3D>(p_spatial) || Object::cast_to<CSGTorus3D>(p_spatial) || Object::cast_to<CSGMesh3D>(p_spatial) || Object::cast_to<CSGPolygon3D>(p_spatial); } -String CSGShapeSpatialGizmoPlugin::get_name() const { - return "CSGShapes"; +String CSGShape3DGizmoPlugin::get_name() const { + return "CSGShape3D"; } -int CSGShapeSpatialGizmoPlugin::get_priority() const { +int CSGShape3DGizmoPlugin::get_priority() const { return -1; } -bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const { +bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const { return true; } -void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - - CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); +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 CSGShape::OPERATION_UNION: + case CSGShape3D::OPERATION_UNION: material = get_material("shape_union_material", p_gizmo); break; - case CSGShape::OPERATION_INTERSECTION: + case CSGShape3D::OPERATION_INTERSECTION: material = get_material("shape_intersection_material", p_gizmo); break; - case CSGShape::OPERATION_SUBTRACTION: + case CSGShape3D::OPERATION_SUBTRACTION: material = get_material("shape_subtraction_material", p_gizmo); break; } Ref<Material> handles_material = get_material("handles"); - PoolVector<Vector3> faces = cs->get_brush_faces(); + Vector<Vector3> faces = cs->get_brush_faces(); Vector<Vector3> lines; lines.resize(faces.size() * 2); { - PoolVector<Vector3>::Read r = faces.read(); + const Vector3 *r = faces.ptr(); for (int i = 0; i < lines.size(); i += 6) { int f = i / 6; @@ -366,13 +381,13 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { Ref<Material> solid_material; switch (cs->get_operation()) { - case CSGShape::OPERATION_UNION: + case CSGShape3D::OPERATION_UNION: solid_material = get_material("shape_union_solid_material", p_gizmo); break; - case CSGShape::OPERATION_INTERSECTION: + case CSGShape3D::OPERATION_INTERSECTION: solid_material = get_material("shape_intersection_solid_material", p_gizmo); break; - case CSGShape::OPERATION_SUBTRACTION: + case CSGShape3D::OPERATION_SUBTRACTION: solid_material = get_material("shape_subtraction_solid_material", p_gizmo); break; } @@ -380,8 +395,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { p_gizmo->add_mesh(mesh, false, Ref<SkinReference>(), solid_material); } - if (Object::cast_to<CSGSphere>(cs)) { - CSGSphere *s = Object::cast_to<CSGSphere>(cs); + if (Object::cast_to<CSGSphere3D>(cs)) { + CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs); float r = s->get_radius(); Vector<Vector3> handles; @@ -389,8 +404,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { p_gizmo->add_handles(handles, handles_material); } - if (Object::cast_to<CSGBox>(cs)) { - CSGBox *s = Object::cast_to<CSGBox>(cs); + if (Object::cast_to<CSGBox3D>(cs)) { + CSGBox3D *s = Object::cast_to<CSGBox3D>(cs); Vector<Vector3> handles; handles.push_back(Vector3(s->get_width() * 0.5, 0, 0)); @@ -399,8 +414,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { p_gizmo->add_handles(handles, handles_material); } - if (Object::cast_to<CSGCylinder>(cs)) { - CSGCylinder *s = Object::cast_to<CSGCylinder>(cs); + if (Object::cast_to<CSGCylinder3D>(cs)) { + CSGCylinder3D *s = Object::cast_to<CSGCylinder3D>(cs); Vector<Vector3> handles; handles.push_back(Vector3(s->get_radius(), 0, 0)); @@ -408,8 +423,8 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { p_gizmo->add_handles(handles, handles_material); } - if (Object::cast_to<CSGTorus>(cs)) { - CSGTorus *s = Object::cast_to<CSGTorus>(cs); + if (Object::cast_to<CSGTorus3D>(cs)) { + CSGTorus3D *s = Object::cast_to<CSGTorus3D>(cs); Vector<Vector3> handles; handles.push_back(Vector3(s->get_inner_radius(), 0, 0)); @@ -419,6 +434,6 @@ void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { } EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) { - Ref<CSGShapeSpatialGizmoPlugin> gizmo_plugin = Ref<CSGShapeSpatialGizmoPlugin>(memnew(CSGShapeSpatialGizmoPlugin)); - SpatialEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); + Ref<CSGShape3DGizmoPlugin> gizmo_plugin = Ref<CSGShape3DGizmoPlugin>(memnew(CSGShape3DGizmoPlugin)); + Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); } diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index d38dafc936..48a414d9c7 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,25 +33,24 @@ #include "csg_shape.h" #include "editor/editor_plugin.h" -#include "editor/spatial_editor_gizmos.h" +#include "editor/node_3d_editor_gizmos.h" -class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - - GDCLASS(CSGShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin); +class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(CSGShape3DGizmoPlugin, EditorNode3DGizmoPlugin); public: - bool has_gizmo(Spatial *p_spatial); + bool has_gizmo(Node3D *p_spatial); String get_name() const; int get_priority() const; bool is_selectable_when_hidden() const; - void redraw(EditorSpatialGizmo *p_gizmo); + void redraw(EditorNode3DGizmo *p_gizmo); - String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; - Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; - void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); - void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel); + String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point); + void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel); - CSGShapeSpatialGizmoPlugin(); + CSGShape3DGizmoPlugin(); }; class EditorPluginCSG : public EditorPlugin { diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 9409b33f24..7df65b04c4 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,112 +29,107 @@ /*************************************************************************/ #include "csg_shape.h" -#include "scene/3d/path.h" +#include "scene/3d/path_3d.h" -void CSGShape::set_use_collision(bool p_enable) { - - if (use_collision == p_enable) +void CSGShape3D::set_use_collision(bool p_enable) { + if (use_collision == p_enable) { return; + } use_collision = p_enable; - if (!is_inside_tree() || !is_root_shape()) + if (!is_inside_tree() || !is_root_shape()) { return; + } if (use_collision) { root_collision_shape.instance(); - root_collision_instance = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC); - PhysicsServer::get_singleton()->body_set_state(root_collision_instance, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform()); - PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); - PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space()); - PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); + root_collision_instance = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC); + PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); + PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); + PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space()); + PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); set_collision_layer(collision_layer); set_collision_mask(collision_mask); _make_dirty(); //force update } else { - PhysicsServer::get_singleton()->free(root_collision_instance); + PhysicsServer3D::get_singleton()->free(root_collision_instance); root_collision_instance = RID(); root_collision_shape.unref(); } _change_notify(); } -bool CSGShape::is_using_collision() const { +bool CSGShape3D::is_using_collision() const { return use_collision; } -void CSGShape::set_collision_layer(uint32_t p_layer) { +void CSGShape3D::set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; if (root_collision_instance.is_valid()) { - PhysicsServer::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer); + PhysicsServer3D::get_singleton()->body_set_collision_layer(root_collision_instance, p_layer); } } -uint32_t CSGShape::get_collision_layer() const { - +uint32_t CSGShape3D::get_collision_layer() const { return collision_layer; } -void CSGShape::set_collision_mask(uint32_t p_mask) { - +void CSGShape3D::set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; if (root_collision_instance.is_valid()) { - PhysicsServer::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask); + PhysicsServer3D::get_singleton()->body_set_collision_mask(root_collision_instance, p_mask); } } -uint32_t CSGShape::get_collision_mask() const { - +uint32_t CSGShape3D::get_collision_mask() const { return collision_mask; } -void CSGShape::set_collision_mask_bit(int p_bit, bool p_value) { - +void CSGShape3D::set_collision_mask_bit(int p_bit, bool p_value) { uint32_t mask = get_collision_mask(); - if (p_value) + if (p_value) { mask |= 1 << p_bit; - else + } else { mask &= ~(1 << p_bit); + } set_collision_mask(mask); } -bool CSGShape::get_collision_mask_bit(int p_bit) const { - +bool CSGShape3D::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } -void CSGShape::set_collision_layer_bit(int p_bit, bool p_value) { - +void CSGShape3D::set_collision_layer_bit(int p_bit, bool p_value) { uint32_t mask = get_collision_layer(); - if (p_value) + if (p_value) { mask |= 1 << p_bit; - else + } else { mask &= ~(1 << p_bit); + } set_collision_layer(mask); } -bool CSGShape::get_collision_layer_bit(int p_bit) const { - +bool CSGShape3D::get_collision_layer_bit(int p_bit) const { return get_collision_layer() & (1 << p_bit); } -bool CSGShape::is_root_shape() const { - +bool CSGShape3D::is_root_shape() const { return !parent; } -void CSGShape::set_snap(float p_snap) { +void CSGShape3D::set_snap(float p_snap) { snap = p_snap; } -float CSGShape::get_snap() const { +float CSGShape3D::get_snap() const { return snap; } -void CSGShape::_make_dirty() { - - if (!is_inside_tree()) +void CSGShape3D::_make_dirty() { + if (!is_inside_tree()) { return; + } if (dirty) { return; @@ -150,34 +145,34 @@ void CSGShape::_make_dirty() { } } -CSGBrush *CSGShape::_get_brush() { - +CSGBrush *CSGShape3D::_get_brush() { if (dirty) { if (brush) { memdelete(brush); } - brush = NULL; + brush = nullptr; CSGBrush *n = _build_brush(); for (int i = 0; i < get_child_count(); i++) { - - CSGShape *child = Object::cast_to<CSGShape>(get_child(i)); - if (!child) + CSGShape3D *child = Object::cast_to<CSGShape3D>(get_child(i)); + if (!child) { continue; - if (!child->is_visible_in_tree()) + } + if (!child->is_visible_in_tree()) { continue; + } CSGBrush *n2 = child->_get_brush(); - if (!n2) + if (!n2) { continue; + } if (!n) { n = memnew(CSGBrush); n->copy_from(*n2, child->get_transform()); } else { - CSGBrush *nn = memnew(CSGBrush); CSGBrush *nn2 = memnew(CSGBrush); nn2->copy_from(*n2, child->get_transform()); @@ -185,9 +180,15 @@ CSGBrush *CSGShape::_get_brush() { CSGBrushOperation bop; switch (child->get_operation()) { - case CSGShape::OPERATION_UNION: bop.merge_brushes(CSGBrushOperation::OPERATION_UNION, *n, *nn2, *nn, snap); break; - case CSGShape::OPERATION_INTERSECTION: bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); break; - case CSGShape::OPERATION_SUBTRACTION: bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); break; + case CSGShape3D::OPERATION_UNION: + bop.merge_brushes(CSGBrushOperation::OPERATION_UNION, *n, *nn2, *nn, snap); + break; + case CSGShape3D::OPERATION_INTERSECTION: + bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); + break; + case CSGShape3D::OPERATION_SUBTRACTION: + bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); + break; } memdelete(n); memdelete(nn2); @@ -199,10 +200,11 @@ CSGBrush *CSGShape::_get_brush() { AABB aabb; for (int i = 0; i < n->faces.size(); i++) { for (int j = 0; j < 3; j++) { - if (i == 0 && j == 0) + if (i == 0 && j == 0) { aabb.position = n->faces[i].vertices[j]; - else + } else { aabb.expand_to(n->faces[i].vertices[j]); + } } } node_aabb = aabb; @@ -218,18 +220,18 @@ CSGBrush *CSGShape::_get_brush() { return brush; } -int CSGShape::mikktGetNumFaces(const SMikkTSpaceContext *pContext) { +int CSGShape3D::mikktGetNumFaces(const SMikkTSpaceContext *pContext) { ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData); return surface.vertices.size() / 3; } -int CSGShape::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) { +int CSGShape3D::mikktGetNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace) { // always 3 return 3; } -void CSGShape::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) { +void CSGShape3D::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosOut[], const int iFace, const int iVert) { ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData); Vector3 v = surface.verticesw[iFace * 3 + iVert]; @@ -238,7 +240,7 @@ void CSGShape::mikktGetPosition(const SMikkTSpaceContext *pContext, float fvPosO fvPosOut[2] = v.z; } -void CSGShape::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) { +void CSGShape3D::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOut[], const int iFace, const int iVert) { ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData); Vector3 n = surface.normalsw[iFace * 3 + iVert]; @@ -247,7 +249,7 @@ void CSGShape::mikktGetNormal(const SMikkTSpaceContext *pContext, float fvNormOu fvNormOut[2] = n.z; } -void CSGShape::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) { +void CSGShape3D::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexcOut[], const int iFace, const int iVert) { ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData); Vector2 t = surface.uvsw[iFace * 3 + iVert]; @@ -255,9 +257,8 @@ void CSGShape::mikktGetTexCoord(const SMikkTSpaceContext *pContext, float fvTexc fvTexcOut[1] = t.y; } -void CSGShape::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, +void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, const tbool bIsOrientationPreserving, const int iFace, const int iVert) { - ShapeUpdateSurface &surface = *((ShapeUpdateSurface *)pContext->m_pUserData); int i = iFace * 3 + iVert; @@ -273,10 +274,10 @@ void CSGShape::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const f surface.tansw[i++] = d < 0 ? -1 : 1; } -void CSGShape::_update_shape() { - - if (parent) +void CSGShape3D::_update_shape() { + if (parent) { return; + } set_base(RID()); root_mesh.unref(); //byebye root mesh @@ -296,20 +297,18 @@ void CSGShape::_update_shape() { int mat = n->faces[i].material; ERR_CONTINUE(mat < -1 || mat >= face_count.size()); int idx = mat == -1 ? face_count.size() - 1 : mat; - if (n->faces[i].smooth) { - Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]); + Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]); - for (int j = 0; j < 3; j++) { - Vector3 v = n->faces[i].vertices[j]; - Vector3 add; - if (vec_map.lookup(v, add)) { - add += p.normal; - } else { - add = p.normal; - } - vec_map.set(v, add); + for (int j = 0; j < 3; j++) { + Vector3 v = n->faces[i].vertices[j]; + Vector3 add; + if (vec_map.lookup(v, add)) { + add += p.normal; + } else { + add = p.normal; } + vec_map.set(v, add); } face_count.write[idx]++; @@ -321,7 +320,6 @@ void CSGShape::_update_shape() { //create arrays for (int i = 0; i < surfaces.size(); i++) { - surfaces.write[i].vertices.resize(face_count[i] * 3); surfaces.write[i].normals.resize(face_count[i] * 3); surfaces.write[i].uvs.resize(face_count[i] * 3); @@ -334,43 +332,44 @@ void CSGShape::_update_shape() { surfaces.write[i].material = n->materials[i]; } - surfaces.write[i].verticesw = surfaces.write[i].vertices.write(); - surfaces.write[i].normalsw = surfaces.write[i].normals.write(); - surfaces.write[i].uvsw = surfaces.write[i].uvs.write(); + surfaces.write[i].verticesw = surfaces.write[i].vertices.ptrw(); + surfaces.write[i].normalsw = surfaces.write[i].normals.ptrw(); + surfaces.write[i].uvsw = surfaces.write[i].uvs.ptrw(); if (calculate_tangents) { - surfaces.write[i].tansw = surfaces.write[i].tans.write(); + surfaces.write[i].tansw = surfaces.write[i].tans.ptrw(); } } - //fill arrays - PoolVector<Vector3> physics_faces; - bool fill_physics_faces = false; + // Update collision faces. if (root_collision_shape.is_valid()) { + Vector<Vector3> physics_faces; physics_faces.resize(n->faces.size() * 3); - fill_physics_faces = true; - } + Vector3 *physicsw = physics_faces.ptrw(); - { - PoolVector<Vector3>::Write physicsw; + for (int i = 0; i < n->faces.size(); i++) { + int order[3] = { 0, 1, 2 }; + + if (n->faces[i].invert) { + SWAP(order[1], order[2]); + } - if (fill_physics_faces) { - physicsw = physics_faces.write(); + physicsw[i * 3 + 0] = n->faces[i].vertices[order[0]]; + physicsw[i * 3 + 1] = n->faces[i].vertices[order[1]]; + physicsw[i * 3 + 2] = n->faces[i].vertices[order[2]]; } - for (int i = 0; i < n->faces.size(); i++) { + root_collision_shape->set_faces(physics_faces); + } + //fill arrays + { + for (int i = 0; i < n->faces.size(); i++) { int order[3] = { 0, 1, 2 }; if (n->faces[i].invert) { SWAP(order[1], order[2]); } - if (fill_physics_faces) { - physicsw[i * 3 + 0] = n->faces[i].vertices[order[0]]; - physicsw[i * 3 + 1] = n->faces[i].vertices[order[1]]; - physicsw[i * 3 + 2] = n->faces[i].vertices[order[2]]; - } - int mat = n->faces[i].material; ERR_CONTINUE(mat < -1 || mat >= face_count.size()); int idx = mat == -1 ? face_count.size() - 1 : mat; @@ -380,7 +379,6 @@ void CSGShape::_update_shape() { Plane p(n->faces[i].vertices[0], n->faces[i].vertices[1], n->faces[i].vertices[2]); for (int j = 0; j < 3; j++) { - Vector3 v = n->faces[i].vertices[j]; Vector3 normal = p.normal; @@ -390,7 +388,6 @@ void CSGShape::_update_shape() { } if (n->faces[i].invert) { - normal = -normal; } @@ -427,7 +424,7 @@ void CSGShape::_update_shape() { mkif.m_getPosition = mikktGetPosition; mkif.m_getTexCoord = mikktGetTexCoord; mkif.m_setTSpace = mikktSetTSpaceDefault; - mkif.m_setTSpaceBasic = NULL; + mkif.m_setTSpaceBasic = nullptr; SMikkTSpaceContext msc; msc.m_pInterface = &mkif; @@ -435,14 +432,9 @@ void CSGShape::_update_shape() { have_tangents = genTangSpaceDefault(&msc); } - // unset write access - surfaces.write[i].verticesw.release(); - surfaces.write[i].normalsw.release(); - surfaces.write[i].uvsw.release(); - surfaces.write[i].tansw.release(); - - if (surfaces[i].last_added == 0) + if (surfaces[i].last_added == 0) { continue; + } // and convert to surface array Array array; @@ -460,28 +452,25 @@ void CSGShape::_update_shape() { root_mesh->surface_set_material(idx, surfaces[i].material); } - if (root_collision_shape.is_valid()) { - root_collision_shape->set_faces(physics_faces); - } - set_base(root_mesh->get_rid()); } -AABB CSGShape::get_aabb() const { + +AABB CSGShape3D::get_aabb() const { return node_aabb; } -PoolVector<Vector3> CSGShape::get_brush_faces() { - ERR_FAIL_COND_V(!is_inside_tree(), PoolVector<Vector3>()); +Vector<Vector3> CSGShape3D::get_brush_faces() { + ERR_FAIL_COND_V(!is_inside_tree(), Vector<Vector3>()); CSGBrush *b = _get_brush(); if (!b) { - return PoolVector<Vector3>(); + return Vector<Vector3>(); } - PoolVector<Vector3> faces; + Vector<Vector3> faces; int fc = b->faces.size(); faces.resize(fc * 3); { - PoolVector<Vector3>::Write w = faces.write(); + Vector3 *w = faces.ptrw(); for (int i = 0; i < fc; i++) { w[i * 3 + 0] = b->faces[i].vertices[0]; w[i * 3 + 1] = b->faces[i].vertices[1]; @@ -492,18 +481,15 @@ PoolVector<Vector3> CSGShape::get_brush_faces() { return faces; } -PoolVector<Face3> CSGShape::get_faces(uint32_t p_usage_flags) const { - - return PoolVector<Face3>(); +Vector<Face3> CSGShape3D::get_faces(uint32_t p_usage_flags) const { + return Vector<Face3>(); } -void CSGShape::_notification(int p_what) { - +void CSGShape3D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - Node *parentn = get_parent(); if (parentn) { - parent = Object::cast_to<CSGShape>(parentn); + parent = Object::cast_to<CSGShape3D>(parentn); if (parent) { set_base(RID()); root_mesh.unref(); @@ -512,11 +498,11 @@ void CSGShape::_notification(int p_what) { if (use_collision && is_root_shape()) { root_collision_shape.instance(); - root_collision_instance = PhysicsServer::get_singleton()->body_create(PhysicsServer::BODY_MODE_STATIC); - PhysicsServer::get_singleton()->body_set_state(root_collision_instance, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform()); - PhysicsServer::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); - PhysicsServer::get_singleton()->body_set_space(root_collision_instance, get_world()->get_space()); - PhysicsServer::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); + root_collision_instance = PhysicsServer3D::get_singleton()->body_create(PhysicsServer3D::BODY_MODE_STATIC); + PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); + PhysicsServer3D::get_singleton()->body_add_shape(root_collision_instance, root_collision_shape->get_rid()); + PhysicsServer3D::get_singleton()->body_set_space(root_collision_instance, get_world_3d()->get_space()); + PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id()); set_collision_layer(collision_layer); set_collision_mask(collision_mask); } @@ -525,27 +511,25 @@ void CSGShape::_notification(int p_what) { } if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (parent) { parent->_make_dirty(); } } if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (parent) { parent->_make_dirty(); } } if (p_what == NOTIFICATION_EXIT_TREE) { - - if (parent) + if (parent) { parent->_make_dirty(); - parent = NULL; + } + parent = nullptr; if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { - PhysicsServer::get_singleton()->free(root_collision_instance); + PhysicsServer3D::get_singleton()->free(root_collision_instance); root_collision_instance = RID(); root_collision_shape.unref(); } @@ -553,27 +537,26 @@ void CSGShape::_notification(int p_what) { } } -void CSGShape::set_operation(Operation p_operation) { - +void CSGShape3D::set_operation(Operation p_operation) { operation = p_operation; _make_dirty(); update_gizmo(); } -CSGShape::Operation CSGShape::get_operation() const { +CSGShape3D::Operation CSGShape3D::get_operation() const { return operation; } -void CSGShape::set_calculate_tangents(bool p_calculate_tangents) { +void CSGShape3D::set_calculate_tangents(bool p_calculate_tangents) { calculate_tangents = p_calculate_tangents; _make_dirty(); } -bool CSGShape::is_calculating_tangents() const { +bool CSGShape3D::is_calculating_tangents() const { return calculate_tangents; } -void CSGShape::_validate_property(PropertyInfo &property) const { +void CSGShape3D::_validate_property(PropertyInfo &property) const { bool is_collision_prefixed = property.name.begins_with("collision_"); if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) { //hide collision if not root @@ -583,8 +566,7 @@ void CSGShape::_validate_property(PropertyInfo &property) const { } } -Array CSGShape::get_meshes() const { - +Array CSGShape3D::get_meshes() const { if (root_mesh.is_valid()) { Array arr; arr.resize(2); @@ -595,39 +577,39 @@ Array CSGShape::get_meshes() const { return Array(); } -void CSGShape::_bind_methods() { - ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape::_update_shape); - ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape::is_root_shape); +void CSGShape3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape3D::_update_shape); + ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape3D::is_root_shape); - ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape::set_operation); - ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape::get_operation); + ClassDB::bind_method(D_METHOD("set_operation", "operation"), &CSGShape3D::set_operation); + ClassDB::bind_method(D_METHOD("get_operation"), &CSGShape3D::get_operation); - ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape::set_snap); - ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape::get_snap); + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CSGShape3D::set_snap); + ClassDB::bind_method(D_METHOD("get_snap"), &CSGShape3D::get_snap); - ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape::set_use_collision); - ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape::is_using_collision); + ClassDB::bind_method(D_METHOD("set_use_collision", "operation"), &CSGShape3D::set_use_collision); + ClassDB::bind_method(D_METHOD("is_using_collision"), &CSGShape3D::is_using_collision); - ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CSGShape::set_collision_layer); - ClassDB::bind_method(D_METHOD("get_collision_layer"), &CSGShape::get_collision_layer); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CSGShape3D::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &CSGShape3D::get_collision_layer); - ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CSGShape::set_collision_mask); - ClassDB::bind_method(D_METHOD("get_collision_mask"), &CSGShape::get_collision_mask); + 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"), &CSGShape::set_collision_mask_bit); - ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CSGShape::get_collision_mask_bit); + 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_layer_bit", "bit", "value"), &CSGShape::set_collision_layer_bit); - ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CSGShape::get_collision_layer_bit); + 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_calculate_tangents", "enabled"), &CSGShape::set_calculate_tangents); - ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape::is_calculating_tangents); + 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); - ClassDB::bind_method(D_METHOD("get_meshes"), &CSGShape::get_meshes); + ClassDB::bind_method(D_METHOD("get_meshes"), &CSGShape3D::get_meshes); ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.0001,1,0.001"), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents"); ADD_GROUP("Collision", "collision_"); @@ -640,10 +622,10 @@ void CSGShape::_bind_methods() { BIND_ENUM_CONSTANT(OPERATION_SUBTRACTION); } -CSGShape::CSGShape() { +CSGShape3D::CSGShape3D() { operation = OPERATION_UNION; - parent = NULL; - brush = NULL; + parent = nullptr; + brush = nullptr; dirty = false; snap = 0.001; use_collision = false; @@ -653,33 +635,32 @@ CSGShape::CSGShape() { set_notify_local_transform(true); } -CSGShape::~CSGShape() { +CSGShape3D::~CSGShape3D() { if (brush) { memdelete(brush); - brush = NULL; + brush = nullptr; } } -////////////////////////////////// -CSGBrush *CSGCombiner::_build_brush() { +////////////////////////////////// - return NULL; //does not build anything +CSGBrush *CSGCombiner3D::_build_brush() { + return nullptr; //does not build anything } -CSGCombiner::CSGCombiner() { +CSGCombiner3D::CSGCombiner3D() { } ///////////////////// -CSGBrush *CSGPrimitive::_create_brush_from_arrays(const PoolVector<Vector3> &p_vertices, const PoolVector<Vector2> &p_uv, const PoolVector<bool> &p_smooth, const PoolVector<Ref<Material> > &p_materials) { - +CSGBrush *CSGPrimitive3D::_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) { CSGBrush *brush = memnew(CSGBrush); - PoolVector<bool> invert; + Vector<bool> invert; invert.resize(p_vertices.size() / 3); { int ic = invert.size(); - PoolVector<bool>::Write w = invert.write(); + bool *w = invert.ptrw(); for (int i = 0; i < ic; i++) { w[i] = invert_faces; } @@ -689,46 +670,45 @@ CSGBrush *CSGPrimitive::_create_brush_from_arrays(const PoolVector<Vector3> &p_v return brush; } -void CSGPrimitive::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive::set_invert_faces); - ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive::is_inverting_faces); +void CSGPrimitive3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive3D::set_invert_faces); + ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive3D::is_inverting_faces); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_faces"), "set_invert_faces", "is_inverting_faces"); } -void CSGPrimitive::set_invert_faces(bool p_invert) { - if (invert_faces == p_invert) +void CSGPrimitive3D::set_invert_faces(bool p_invert) { + if (invert_faces == p_invert) { return; + } invert_faces = p_invert; _make_dirty(); } -bool CSGPrimitive::is_inverting_faces() { +bool CSGPrimitive3D::is_inverting_faces() { return invert_faces; } -CSGPrimitive::CSGPrimitive() { +CSGPrimitive3D::CSGPrimitive3D() { invert_faces = false; } ///////////////////// -CSGBrush *CSGMesh::_build_brush() { - - if (!mesh.is_valid()) - return NULL; +CSGBrush *CSGMesh3D::_build_brush() { + if (!mesh.is_valid()) { + return nullptr; + } - PoolVector<Vector3> vertices; - PoolVector<bool> smooth; - PoolVector<Ref<Material> > materials; - PoolVector<Vector2> uvs; + Vector<Vector3> vertices; + Vector<bool> smooth; + Vector<Ref<Material>> materials; + Vector<Vector2> uvs; Ref<Material> material = get_material(); for (int i = 0; i < mesh->get_surface_count(); i++) { - if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { continue; } @@ -737,29 +717,26 @@ CSGBrush *CSGMesh::_build_brush() { if (arrays.size() == 0) { _make_dirty(); - ERR_FAIL_COND_V(arrays.size() == 0, NULL); + ERR_FAIL_COND_V(arrays.size() == 0, nullptr); } - PoolVector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX]; - if (avertices.size() == 0) + Vector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX]; + if (avertices.size() == 0) { continue; + } - PoolVector<Vector3>::Read vr = avertices.read(); + const Vector3 *vr = avertices.ptr(); - PoolVector<Vector3> anormals = arrays[Mesh::ARRAY_NORMAL]; - PoolVector<Vector3>::Read nr; - bool nr_used = false; + Vector<Vector3> anormals = arrays[Mesh::ARRAY_NORMAL]; + const Vector3 *nr = nullptr; if (anormals.size()) { - nr = anormals.read(); - nr_used = true; + nr = anormals.ptr(); } - PoolVector<Vector2> auvs = arrays[Mesh::ARRAY_TEX_UV]; - PoolVector<Vector2>::Read uvr; - bool uvr_used = false; + Vector<Vector2> auvs = arrays[Mesh::ARRAY_TEX_UV]; + const Vector2 *uvr = nullptr; if (auvs.size()) { - uvr = auvs.read(); - uvr_used = true; + uvr = auvs.ptr(); } Ref<Material> mat; @@ -769,7 +746,7 @@ CSGBrush *CSGMesh::_build_brush() { mat = mesh->surface_get_material(i); } - PoolVector<int> aindices = arrays[Mesh::ARRAY_INDEX]; + Vector<int> aindices = arrays[Mesh::ARRAY_INDEX]; if (aindices.size()) { int as = vertices.size(); int is = aindices.size(); @@ -779,15 +756,14 @@ CSGBrush *CSGMesh::_build_brush() { materials.resize((as + is) / 3); uvs.resize(as + is); - PoolVector<Vector3>::Write vw = vertices.write(); - PoolVector<bool>::Write sw = smooth.write(); - PoolVector<Vector2>::Write uvw = uvs.write(); - PoolVector<Ref<Material> >::Write mw = materials.write(); + Vector3 *vw = vertices.ptrw(); + bool *sw = smooth.ptrw(); + Vector2 *uvw = uvs.ptrw(); + Ref<Material> *mw = materials.ptrw(); - PoolVector<int>::Read ir = aindices.read(); + const int *ir = aindices.ptr(); for (int j = 0; j < is; j += 3) { - Vector3 vertex[3]; Vector3 normal[3]; Vector2 uv[3]; @@ -795,10 +771,10 @@ CSGBrush *CSGMesh::_build_brush() { for (int k = 0; k < 3; k++) { int idx = ir[j + k]; vertex[k] = vr[idx]; - if (nr_used) { + if (nr) { normal[k] = nr[idx]; } - if (uvr_used) { + if (uvr) { uv[k] = uvr[idx]; } } @@ -825,23 +801,22 @@ CSGBrush *CSGMesh::_build_brush() { uvs.resize(as + is); materials.resize((as + is) / 3); - PoolVector<Vector3>::Write vw = vertices.write(); - PoolVector<bool>::Write sw = smooth.write(); - PoolVector<Vector2>::Write uvw = uvs.write(); - PoolVector<Ref<Material> >::Write mw = materials.write(); + Vector3 *vw = vertices.ptrw(); + bool *sw = smooth.ptrw(); + Vector2 *uvw = uvs.ptrw(); + Ref<Material> *mw = materials.ptrw(); for (int j = 0; j < is; j += 3) { - Vector3 vertex[3]; Vector3 normal[3]; Vector2 uv[3]; for (int k = 0; k < 3; k++) { vertex[k] = vr[j + k]; - if (nr_used) { + if (nr) { normal[k] = nr[j + k]; } - if (uvr_used) { + if (uvr) { uv[k] = uvr[j + k]; } } @@ -862,67 +837,64 @@ CSGBrush *CSGMesh::_build_brush() { } } - if (vertices.size() == 0) - return NULL; + if (vertices.size() == 0) { + return nullptr; + } return _create_brush_from_arrays(vertices, uvs, smooth, materials); } -void CSGMesh::_mesh_changed() { +void CSGMesh3D::_mesh_changed() { _make_dirty(); update_gizmo(); } -void CSGMesh::set_material(const Ref<Material> &p_material) { - if (material == p_material) +void CSGMesh3D::set_material(const Ref<Material> &p_material) { + if (material == p_material) { return; + } material = p_material; _make_dirty(); } -Ref<Material> CSGMesh::get_material() const { - +Ref<Material> CSGMesh3D::get_material() const { return material; } -void CSGMesh::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CSGMesh::set_mesh); - ClassDB::bind_method(D_METHOD("get_mesh"), &CSGMesh::get_mesh); - - ClassDB::bind_method(D_METHOD("_mesh_changed"), &CSGMesh::_mesh_changed); +void CSGMesh3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CSGMesh3D::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &CSGMesh3D::get_mesh); - ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGMesh::set_material); - ClassDB::bind_method(D_METHOD("get_material"), &CSGMesh::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGMesh3D::set_material); + 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, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); } -void CSGMesh::set_mesh(const Ref<Mesh> &p_mesh) { - - if (mesh == p_mesh) +void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) { + if (mesh == p_mesh) { return; + } if (mesh.is_valid()) { - mesh->disconnect("changed", this, "_mesh_changed"); + mesh->disconnect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed)); } mesh = p_mesh; if (mesh.is_valid()) { - mesh->connect("changed", this, "_mesh_changed"); + mesh->connect("changed", callable_mp(this, &CSGMesh3D::_mesh_changed)); } _make_dirty(); } -Ref<Mesh> CSGMesh::get_mesh() { +Ref<Mesh> CSGMesh3D::get_mesh() { return mesh; } //////////////////////////////// -CSGBrush *CSGSphere::_build_brush() { - +CSGBrush *CSGSphere3D::_build_brush() { // set our bounding box CSGBrush *brush = memnew(CSGBrush); @@ -932,11 +904,11 @@ CSGBrush *CSGSphere::_build_brush() { bool invert_val = is_inverting_faces(); Ref<Material> material = get_material(); - PoolVector<Vector3> faces; - PoolVector<Vector2> uvs; - PoolVector<bool> smooth; - PoolVector<Ref<Material> > materials; - PoolVector<bool> invert; + Vector<Vector3> faces; + Vector<Vector2> uvs; + Vector<bool> smooth; + Vector<Ref<Material>> materials; + Vector<bool> invert; faces.resize(face_count * 3); uvs.resize(face_count * 3); @@ -946,12 +918,11 @@ CSGBrush *CSGSphere::_build_brush() { invert.resize(face_count); { - - PoolVector<Vector3>::Write facesw = faces.write(); - PoolVector<Vector2>::Write uvsw = uvs.write(); - PoolVector<bool>::Write smoothw = smooth.write(); - PoolVector<Ref<Material> >::Write materialsw = materials.write(); - PoolVector<bool>::Write invertw = invert.write(); + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); int face = 0; @@ -967,7 +938,6 @@ CSGBrush *CSGSphere::_build_brush() { double u1 = double(i) / rings; for (int j = radial_segments; j >= 1; j--) { - double lng0 = 2 * Math_PI * (double)(j - 1) / radial_segments; double x0 = Math::cos(lng0); double y0 = Math::sin(lng0); @@ -994,7 +964,6 @@ CSGBrush *CSGSphere::_build_brush() { }; if (i < rings) { - //face 1 facesw[face * 3 + 0] = v[0]; facesw[face * 3 + 1] = v[1]; @@ -1040,29 +1009,29 @@ CSGBrush *CSGSphere::_build_brush() { return brush; } -void CSGSphere::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGSphere::set_radius); - ClassDB::bind_method(D_METHOD("get_radius"), &CSGSphere::get_radius); +void CSGSphere3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGSphere3D::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &CSGSphere3D::get_radius); - ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &CSGSphere::set_radial_segments); - ClassDB::bind_method(D_METHOD("get_radial_segments"), &CSGSphere::get_radial_segments); - ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CSGSphere::set_rings); - ClassDB::bind_method(D_METHOD("get_rings"), &CSGSphere::get_rings); + ClassDB::bind_method(D_METHOD("set_radial_segments", "radial_segments"), &CSGSphere3D::set_radial_segments); + ClassDB::bind_method(D_METHOD("get_radial_segments"), &CSGSphere3D::get_radial_segments); + ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CSGSphere3D::set_rings); + ClassDB::bind_method(D_METHOD("get_rings"), &CSGSphere3D::get_rings); - ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGSphere::set_smooth_faces); - ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGSphere::get_smooth_faces); + ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGSphere3D::set_smooth_faces); + ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGSphere3D::get_smooth_faces); - ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGSphere::set_material); - ClassDB::bind_method(D_METHOD("get_material"), &CSGSphere::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGSphere3D::set_material); + ClassDB::bind_method(D_METHOD("get_material"), &CSGSphere3D::get_material); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius"); 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, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); } -void CSGSphere::set_radius(const float p_radius) { +void CSGSphere3D::set_radius(const float p_radius) { ERR_FAIL_COND(p_radius <= 0); radius = p_radius; _make_dirty(); @@ -1070,51 +1039,49 @@ void CSGSphere::set_radius(const float p_radius) { _change_notify("radius"); } -float CSGSphere::get_radius() const { +float CSGSphere3D::get_radius() const { return radius; } -void CSGSphere::set_radial_segments(const int p_radial_segments) { +void CSGSphere3D::set_radial_segments(const int p_radial_segments) { radial_segments = p_radial_segments > 4 ? p_radial_segments : 4; _make_dirty(); update_gizmo(); } -int CSGSphere::get_radial_segments() const { +int CSGSphere3D::get_radial_segments() const { return radial_segments; } -void CSGSphere::set_rings(const int p_rings) { +void CSGSphere3D::set_rings(const int p_rings) { rings = p_rings > 1 ? p_rings : 1; _make_dirty(); update_gizmo(); } -int CSGSphere::get_rings() const { +int CSGSphere3D::get_rings() const { return rings; } -void CSGSphere::set_smooth_faces(const bool p_smooth_faces) { +void CSGSphere3D::set_smooth_faces(const bool p_smooth_faces) { smooth_faces = p_smooth_faces; _make_dirty(); } -bool CSGSphere::get_smooth_faces() const { +bool CSGSphere3D::get_smooth_faces() const { return smooth_faces; } -void CSGSphere::set_material(const Ref<Material> &p_material) { - +void CSGSphere3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); } -Ref<Material> CSGSphere::get_material() const { - +Ref<Material> CSGSphere3D::get_material() const { return material; } -CSGSphere::CSGSphere() { +CSGSphere3D::CSGSphere3D() { // defaults radius = 1.0; radial_segments = 12; @@ -1124,8 +1091,7 @@ CSGSphere::CSGSphere() { /////////////// -CSGBrush *CSGBox::_build_brush() { - +CSGBrush *CSGBox3D::_build_brush() { // set our bounding box CSGBrush *brush = memnew(CSGBrush); @@ -1135,11 +1101,11 @@ CSGBrush *CSGBox::_build_brush() { bool invert_val = is_inverting_faces(); Ref<Material> material = get_material(); - PoolVector<Vector3> faces; - PoolVector<Vector2> uvs; - PoolVector<bool> smooth; - PoolVector<Ref<Material> > materials; - PoolVector<bool> invert; + Vector<Vector3> faces; + Vector<Vector2> uvs; + Vector<bool> smooth; + Vector<Ref<Material>> materials; + Vector<bool> invert; faces.resize(face_count * 3); uvs.resize(face_count * 3); @@ -1149,37 +1115,33 @@ CSGBrush *CSGBox::_build_brush() { invert.resize(face_count); { - - PoolVector<Vector3>::Write facesw = faces.write(); - PoolVector<Vector2>::Write uvsw = uvs.write(); - PoolVector<bool>::Write smoothw = smooth.write(); - PoolVector<Ref<Material> >::Write materialsw = materials.write(); - PoolVector<bool>::Write invertw = invert.write(); + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); int face = 0; Vector3 vertex_mul(width * 0.5, height * 0.5, depth * 0.5); { - for (int i = 0; i < 6; i++) { - Vector3 face_points[4]; float uv_points[8] = { 0, 0, 0, 1, 1, 1, 1, 0 }; for (int j = 0; j < 4; j++) { - float v[3]; v[0] = 1.0; v[1] = 1 - 2 * ((j >> 1) & 1); v[2] = v[1] * (1 - 2 * (j & 1)); for (int k = 0; k < 3; k++) { - - if (i < 3) + if (i < 3) { face_points[j][(i + k) % 3] = v[k]; - else + } else { face_points[3 - j][(i + k) % 3] = -v[k]; + } } } @@ -1229,71 +1191,69 @@ CSGBrush *CSGBox::_build_brush() { return brush; } -void CSGBox::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_width", "width"), &CSGBox::set_width); - ClassDB::bind_method(D_METHOD("get_width"), &CSGBox::get_width); +void CSGBox3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_width", "width"), &CSGBox3D::set_width); + ClassDB::bind_method(D_METHOD("get_width"), &CSGBox3D::get_width); - ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGBox::set_height); - ClassDB::bind_method(D_METHOD("get_height"), &CSGBox::get_height); + ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGBox3D::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &CSGBox3D::get_height); - ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGBox::set_depth); - ClassDB::bind_method(D_METHOD("get_depth"), &CSGBox::get_depth); + ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGBox3D::set_depth); + ClassDB::bind_method(D_METHOD("get_depth"), &CSGBox3D::get_depth); - ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox::set_material); - ClassDB::bind_method(D_METHOD("get_material"), &CSGBox::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGBox3D::set_material); + ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "width", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); } -void CSGBox::set_width(const float p_width) { +void CSGBox3D::set_width(const float p_width) { width = p_width; _make_dirty(); update_gizmo(); _change_notify("width"); } -float CSGBox::get_width() const { +float CSGBox3D::get_width() const { return width; } -void CSGBox::set_height(const float p_height) { +void CSGBox3D::set_height(const float p_height) { height = p_height; _make_dirty(); update_gizmo(); _change_notify("height"); } -float CSGBox::get_height() const { +float CSGBox3D::get_height() const { return height; } -void CSGBox::set_depth(const float p_depth) { +void CSGBox3D::set_depth(const float p_depth) { depth = p_depth; _make_dirty(); update_gizmo(); _change_notify("depth"); } -float CSGBox::get_depth() const { +float CSGBox3D::get_depth() const { return depth; } -void CSGBox::set_material(const Ref<Material> &p_material) { - +void CSGBox3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); update_gizmo(); } -Ref<Material> CSGBox::get_material() const { - +Ref<Material> CSGBox3D::get_material() const { return material; } -CSGBox::CSGBox() { +CSGBox3D::CSGBox3D() { // defaults width = 2.0; height = 2.0; @@ -1302,8 +1262,7 @@ CSGBox::CSGBox() { /////////////// -CSGBrush *CSGCylinder::_build_brush() { - +CSGBrush *CSGCylinder3D::_build_brush() { // set our bounding box CSGBrush *brush = memnew(CSGBrush); @@ -1313,11 +1272,11 @@ CSGBrush *CSGCylinder::_build_brush() { bool invert_val = is_inverting_faces(); Ref<Material> material = get_material(); - PoolVector<Vector3> faces; - PoolVector<Vector2> uvs; - PoolVector<bool> smooth; - PoolVector<Ref<Material> > materials; - PoolVector<bool> invert; + Vector<Vector3> faces; + Vector<Vector2> uvs; + Vector<bool> smooth; + Vector<Ref<Material>> materials; + Vector<bool> invert; faces.resize(face_count * 3); uvs.resize(face_count * 3); @@ -1327,21 +1286,18 @@ CSGBrush *CSGCylinder::_build_brush() { invert.resize(face_count); { - - PoolVector<Vector3>::Write facesw = faces.write(); - PoolVector<Vector2>::Write uvsw = uvs.write(); - PoolVector<bool>::Write smoothw = smooth.write(); - PoolVector<Ref<Material> >::Write materialsw = materials.write(); - PoolVector<bool>::Write invertw = invert.write(); + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); int face = 0; Vector3 vertex_mul(radius, height * 0.5, radius); { - for (int i = 0; i < sides; i++) { - float inc = float(i) / sides; float inc_n = float((i + 1)) / sides; @@ -1438,97 +1394,95 @@ CSGBrush *CSGCylinder::_build_brush() { return brush; } -void CSGCylinder::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGCylinder::set_radius); - ClassDB::bind_method(D_METHOD("get_radius"), &CSGCylinder::get_radius); +void CSGCylinder3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CSGCylinder3D::set_radius); + ClassDB::bind_method(D_METHOD("get_radius"), &CSGCylinder3D::get_radius); - ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGCylinder::set_height); - ClassDB::bind_method(D_METHOD("get_height"), &CSGCylinder::get_height); + ClassDB::bind_method(D_METHOD("set_height", "height"), &CSGCylinder3D::set_height); + ClassDB::bind_method(D_METHOD("get_height"), &CSGCylinder3D::get_height); - ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGCylinder::set_sides); - ClassDB::bind_method(D_METHOD("get_sides"), &CSGCylinder::get_sides); + ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGCylinder3D::set_sides); + ClassDB::bind_method(D_METHOD("get_sides"), &CSGCylinder3D::get_sides); - ClassDB::bind_method(D_METHOD("set_cone", "cone"), &CSGCylinder::set_cone); - ClassDB::bind_method(D_METHOD("is_cone"), &CSGCylinder::is_cone); + ClassDB::bind_method(D_METHOD("set_cone", "cone"), &CSGCylinder3D::set_cone); + ClassDB::bind_method(D_METHOD("is_cone"), &CSGCylinder3D::is_cone); - ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGCylinder::set_material); - ClassDB::bind_method(D_METHOD("get_material"), &CSGCylinder::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGCylinder3D::set_material); + ClassDB::bind_method(D_METHOD("get_material"), &CSGCylinder3D::get_material); - ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder::set_smooth_faces); - ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder::get_smooth_faces); + 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::REAL, "radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "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_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::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, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); } -void CSGCylinder::set_radius(const float p_radius) { +void CSGCylinder3D::set_radius(const float p_radius) { radius = p_radius; _make_dirty(); update_gizmo(); _change_notify("radius"); } -float CSGCylinder::get_radius() const { +float CSGCylinder3D::get_radius() const { return radius; } -void CSGCylinder::set_height(const float p_height) { +void CSGCylinder3D::set_height(const float p_height) { height = p_height; _make_dirty(); update_gizmo(); _change_notify("height"); } -float CSGCylinder::get_height() const { +float CSGCylinder3D::get_height() const { return height; } -void CSGCylinder::set_sides(const int p_sides) { +void CSGCylinder3D::set_sides(const int p_sides) { ERR_FAIL_COND(p_sides < 3); sides = p_sides; _make_dirty(); update_gizmo(); } -int CSGCylinder::get_sides() const { +int CSGCylinder3D::get_sides() const { return sides; } -void CSGCylinder::set_cone(const bool p_cone) { +void CSGCylinder3D::set_cone(const bool p_cone) { cone = p_cone; _make_dirty(); update_gizmo(); } -bool CSGCylinder::is_cone() const { +bool CSGCylinder3D::is_cone() const { return cone; } -void CSGCylinder::set_smooth_faces(const bool p_smooth_faces) { +void CSGCylinder3D::set_smooth_faces(const bool p_smooth_faces) { smooth_faces = p_smooth_faces; _make_dirty(); } -bool CSGCylinder::get_smooth_faces() const { +bool CSGCylinder3D::get_smooth_faces() const { return smooth_faces; } -void CSGCylinder::set_material(const Ref<Material> &p_material) { - +void CSGCylinder3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); } -Ref<Material> CSGCylinder::get_material() const { - +Ref<Material> CSGCylinder3D::get_material() const { return material; } -CSGCylinder::CSGCylinder() { +CSGCylinder3D::CSGCylinder3D() { // defaults radius = 1.0; height = 1.0; @@ -1539,15 +1493,15 @@ CSGCylinder::CSGCylinder() { /////////////// -CSGBrush *CSGTorus::_build_brush() { - +CSGBrush *CSGTorus3D::_build_brush() { // set our bounding box float min_radius = inner_radius; float max_radius = outer_radius; - if (min_radius == max_radius) - return NULL; //sorry, can't + if (min_radius == max_radius) { + return nullptr; //sorry, can't + } if (min_radius > max_radius) { SWAP(min_radius, max_radius); @@ -1562,11 +1516,11 @@ CSGBrush *CSGTorus::_build_brush() { bool invert_val = is_inverting_faces(); Ref<Material> material = get_material(); - PoolVector<Vector3> faces; - PoolVector<Vector2> uvs; - PoolVector<bool> smooth; - PoolVector<Ref<Material> > materials; - PoolVector<bool> invert; + Vector<Vector3> faces; + Vector<Vector2> uvs; + Vector<bool> smooth; + Vector<Ref<Material>> materials; + Vector<bool> invert; faces.resize(face_count * 3); uvs.resize(face_count * 3); @@ -1576,19 +1530,16 @@ CSGBrush *CSGTorus::_build_brush() { invert.resize(face_count); { - - PoolVector<Vector3>::Write facesw = faces.write(); - PoolVector<Vector2>::Write uvsw = uvs.write(); - PoolVector<bool>::Write smoothw = smooth.write(); - PoolVector<Ref<Material> >::Write materialsw = materials.write(); - PoolVector<bool>::Write invertw = invert.write(); + Vector3 *facesw = faces.ptrw(); + Vector2 *uvsw = uvs.ptrw(); + bool *smoothw = smooth.ptrw(); + Ref<Material> *materialsw = materials.ptrw(); + bool *invertw = invert.ptrw(); int face = 0; { - for (int i = 0; i < sides; i++) { - float inci = float(i) / sides; float inci_n = float((i + 1)) / sides; @@ -1599,7 +1550,6 @@ CSGBrush *CSGTorus::_build_brush() { Vector3 normali_n = Vector3(Math::cos(angi_n), 0, Math::sin(angi_n)); for (int j = 0; j < ring_sides; j++) { - float incj = float(j) / ring_sides; float incj_n = float((j + 1)) / ring_sides; @@ -1665,98 +1615,96 @@ CSGBrush *CSGTorus::_build_brush() { return brush; } -void CSGTorus::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &CSGTorus::set_inner_radius); - ClassDB::bind_method(D_METHOD("get_inner_radius"), &CSGTorus::get_inner_radius); +void CSGTorus3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &CSGTorus3D::set_inner_radius); + ClassDB::bind_method(D_METHOD("get_inner_radius"), &CSGTorus3D::get_inner_radius); - ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &CSGTorus::set_outer_radius); - ClassDB::bind_method(D_METHOD("get_outer_radius"), &CSGTorus::get_outer_radius); + ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &CSGTorus3D::set_outer_radius); + ClassDB::bind_method(D_METHOD("get_outer_radius"), &CSGTorus3D::get_outer_radius); - ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGTorus::set_sides); - ClassDB::bind_method(D_METHOD("get_sides"), &CSGTorus::get_sides); + ClassDB::bind_method(D_METHOD("set_sides", "sides"), &CSGTorus3D::set_sides); + ClassDB::bind_method(D_METHOD("get_sides"), &CSGTorus3D::get_sides); - ClassDB::bind_method(D_METHOD("set_ring_sides", "sides"), &CSGTorus::set_ring_sides); - ClassDB::bind_method(D_METHOD("get_ring_sides"), &CSGTorus::get_ring_sides); + ClassDB::bind_method(D_METHOD("set_ring_sides", "sides"), &CSGTorus3D::set_ring_sides); + ClassDB::bind_method(D_METHOD("get_ring_sides"), &CSGTorus3D::get_ring_sides); - ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGTorus::set_material); - ClassDB::bind_method(D_METHOD("get_material"), &CSGTorus::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGTorus3D::set_material); + ClassDB::bind_method(D_METHOD("get_material"), &CSGTorus3D::get_material); - ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus::set_smooth_faces); - ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus::get_smooth_faces); + 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::REAL, "inner_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "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_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::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, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); } -void CSGTorus::set_inner_radius(const float p_inner_radius) { +void CSGTorus3D::set_inner_radius(const float p_inner_radius) { inner_radius = p_inner_radius; _make_dirty(); update_gizmo(); _change_notify("inner_radius"); } -float CSGTorus::get_inner_radius() const { +float CSGTorus3D::get_inner_radius() const { return inner_radius; } -void CSGTorus::set_outer_radius(const float p_outer_radius) { +void CSGTorus3D::set_outer_radius(const float p_outer_radius) { outer_radius = p_outer_radius; _make_dirty(); update_gizmo(); _change_notify("outer_radius"); } -float CSGTorus::get_outer_radius() const { +float CSGTorus3D::get_outer_radius() const { return outer_radius; } -void CSGTorus::set_sides(const int p_sides) { +void CSGTorus3D::set_sides(const int p_sides) { ERR_FAIL_COND(p_sides < 3); sides = p_sides; _make_dirty(); update_gizmo(); } -int CSGTorus::get_sides() const { +int CSGTorus3D::get_sides() const { return sides; } -void CSGTorus::set_ring_sides(const int p_ring_sides) { +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(); } -int CSGTorus::get_ring_sides() const { +int CSGTorus3D::get_ring_sides() const { return ring_sides; } -void CSGTorus::set_smooth_faces(const bool p_smooth_faces) { +void CSGTorus3D::set_smooth_faces(const bool p_smooth_faces) { smooth_faces = p_smooth_faces; _make_dirty(); } -bool CSGTorus::get_smooth_faces() const { +bool CSGTorus3D::get_smooth_faces() const { return smooth_faces; } -void CSGTorus::set_material(const Ref<Material> &p_material) { - +void CSGTorus3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); } -Ref<Material> CSGTorus::get_material() const { - +Ref<Material> CSGTorus3D::get_material() const { return material; } -CSGTorus::CSGTorus() { +CSGTorus3D::CSGTorus3D() { // defaults inner_radius = 2.0; outer_radius = 3.0; @@ -1767,12 +1715,12 @@ CSGTorus::CSGTorus() { /////////////// -CSGBrush *CSGPolygon::_build_brush() { - +CSGBrush *CSGPolygon3D::_build_brush() { // set our bounding box - if (polygon.size() < 3) - return NULL; + if (polygon.size() < 3) { + return nullptr; + } Vector<Point2> final_polygon = polygon; @@ -1782,10 +1730,11 @@ CSGBrush *CSGPolygon::_build_brush() { Vector<int> triangles = Geometry::triangulate_polygon(final_polygon); - if (triangles.size() < 3) - return NULL; + if (triangles.size() < 3) { + return nullptr; + } - Path *path = NULL; + Path3D *path = nullptr; Ref<Curve3D> curve; // get bounds for our polygon @@ -1797,51 +1746,68 @@ CSGBrush *CSGPolygon::_build_brush() { 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_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 (p.y > final_polygon_max.y) final_polygon_max.y = p.y; + if (p.x > final_polygon_max.x) { + final_polygon_max.x = p.x; + } + if (p.y > final_polygon_max.y) { + final_polygon_max.y = p.y; + } } } Vector2 final_polygon_size = final_polygon_max - final_polygon_min; if (mode == MODE_PATH) { - if (!has_node(path_node)) - return NULL; + if (!has_node(path_node)) { + return nullptr; + } Node *n = get_node(path_node); - if (!n) - return NULL; - path = Object::cast_to<Path>(n); - if (!path) - return NULL; + if (!n) { + return nullptr; + } + path = Object::cast_to<Path3D>(n); + if (!path) { + return nullptr; + } if (path != path_cache) { if (path_cache) { - path_cache->disconnect("tree_exited", this, "_path_exited"); - path_cache->disconnect("curve_changed", this, "_path_changed"); - path_cache = NULL; + 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", this, "_path_exited"); - path_cache->connect("curve_changed", this, "_path_changed"); - path_cache = NULL; + 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 NULL; - if (curve->get_baked_length() <= 0) - return NULL; + if (curve.is_null()) { + return nullptr; + } + if (curve->get_baked_length() <= 0) { + return nullptr; + } } CSGBrush *brush = memnew(CSGBrush); int face_count = 0; switch (mode) { - case MODE_DEPTH: face_count = triangles.size() * 2 / 3 + (final_polygon.size()) * 2; break; - case MODE_SPIN: face_count = (spin_degrees < 360 ? triangles.size() * 2 / 3 : 0) + (final_polygon.size()) * 2 * spin_sides; break; + case MODE_DEPTH: + face_count = triangles.size() * 2 / 3 + (final_polygon.size()) * 2; + break; + case MODE_SPIN: + face_count = (spin_degrees < 360 ? triangles.size() * 2 / 3 : 0) + (final_polygon.size()) * 2 * spin_sides; + break; case MODE_PATH: { float bl = curve->get_baked_length(); int splits = MAX(2, Math::ceil(bl / path_interval)); @@ -1856,11 +1822,11 @@ CSGBrush *CSGPolygon::_build_brush() { bool invert_val = is_inverting_faces(); Ref<Material> material = get_material(); - PoolVector<Vector3> faces; - PoolVector<Vector2> uvs; - PoolVector<bool> smooth; - PoolVector<Ref<Material> > materials; - PoolVector<bool> invert; + Vector<Vector3> faces; + Vector<Vector2> uvs; + Vector<bool> smooth; + Vector<Ref<Material>> materials; + Vector<bool> invert; faces.resize(face_count * 3); uvs.resize(face_count * 3); @@ -1871,21 +1837,18 @@ CSGBrush *CSGPolygon::_build_brush() { AABB aabb; //must be computed { - - PoolVector<Vector3>::Write facesw = faces.write(); - PoolVector<Vector2>::Write uvsw = uvs.write(); - PoolVector<bool>::Write smoothw = smooth.write(); - PoolVector<Ref<Material> >::Write materialsw = materials.write(); - PoolVector<bool>::Write invertw = invert.write(); + 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 }; @@ -1910,7 +1873,6 @@ CSGBrush *CSGPolygon::_build_brush() { //add triangles for depth for (int i = 0; i < final_polygon.size(); i++) { - int i_n = (i + 1) % final_polygon.size(); Vector3 v[4] = { @@ -1960,9 +1922,7 @@ CSGBrush *CSGPolygon::_build_brush() { } 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; @@ -1974,7 +1934,6 @@ CSGBrush *CSGPolygon::_build_brush() { //add triangles for depth for (int j = 0; j < final_polygon.size(); j++) { - int j_n = (j + 1) % final_polygon.size(); Vector3 v[4] = { @@ -2023,7 +1982,6 @@ CSGBrush *CSGPolygon::_build_brush() { } 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 }; @@ -2041,7 +1999,6 @@ CSGBrush *CSGPolygon::_build_brush() { } 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 }; @@ -2061,7 +2018,6 @@ CSGBrush *CSGPolygon::_build_brush() { } } break; case MODE_PATH: { - float bl = curve->get_baked_length(); int splits = MAX(2, Math::ceil(bl / path_interval)); float u1 = 0.0; @@ -2087,7 +2043,6 @@ CSGBrush *CSGPolygon::_build_brush() { } for (int i = 0; i <= splits; i++) { - float ofs = i * path_interval; if (ofs > bl) { ofs = bl; @@ -2127,7 +2082,6 @@ CSGBrush *CSGPolygon::_build_brush() { //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] = { @@ -2177,7 +2131,6 @@ CSGBrush *CSGPolygon::_build_brush() { } 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 }; @@ -2195,7 +2148,6 @@ CSGBrush *CSGPolygon::_build_brush() { } 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 }; @@ -2239,17 +2191,17 @@ CSGBrush *CSGPolygon::_build_brush() { return brush; } -void CSGPolygon::_notification(int p_what) { +void CSGPolygon3D::_notification(int p_what) { if (p_what == NOTIFICATION_EXIT_TREE) { if (path_cache) { - path_cache->disconnect("tree_exited", this, "_path_exited"); - path_cache->disconnect("curve_changed", this, "_path_changed"); - path_cache = NULL; + 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; } } } -void CSGPolygon::_validate_property(PropertyInfo &property) const { +void CSGPolygon3D::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("spin") && mode != MODE_SPIN) { property.usage = 0; } @@ -2260,77 +2212,74 @@ void CSGPolygon::_validate_property(PropertyInfo &property) const { property.usage = 0; } - CSGShape::_validate_property(property); + CSGShape3D::_validate_property(property); } -void CSGPolygon::_path_changed() { +void CSGPolygon3D::_path_changed() { _make_dirty(); update_gizmo(); } -void CSGPolygon::_path_exited() { - path_cache = NULL; +void CSGPolygon3D::_path_exited() { + path_cache = nullptr; } -void CSGPolygon::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CSGPolygon::set_polygon); - ClassDB::bind_method(D_METHOD("get_polygon"), &CSGPolygon::get_polygon); +void CSGPolygon3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CSGPolygon3D::set_polygon); + ClassDB::bind_method(D_METHOD("get_polygon"), &CSGPolygon3D::get_polygon); - ClassDB::bind_method(D_METHOD("set_mode", "mode"), &CSGPolygon::set_mode); - ClassDB::bind_method(D_METHOD("get_mode"), &CSGPolygon::get_mode); + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &CSGPolygon3D::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &CSGPolygon3D::get_mode); - ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGPolygon::set_depth); - ClassDB::bind_method(D_METHOD("get_depth"), &CSGPolygon::get_depth); + ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CSGPolygon3D::set_depth); + ClassDB::bind_method(D_METHOD("get_depth"), &CSGPolygon3D::get_depth); - ClassDB::bind_method(D_METHOD("set_spin_degrees", "degrees"), &CSGPolygon::set_spin_degrees); - ClassDB::bind_method(D_METHOD("get_spin_degrees"), &CSGPolygon::get_spin_degrees); + ClassDB::bind_method(D_METHOD("set_spin_degrees", "degrees"), &CSGPolygon3D::set_spin_degrees); + ClassDB::bind_method(D_METHOD("get_spin_degrees"), &CSGPolygon3D::get_spin_degrees); - ClassDB::bind_method(D_METHOD("set_spin_sides", "spin_sides"), &CSGPolygon::set_spin_sides); - ClassDB::bind_method(D_METHOD("get_spin_sides"), &CSGPolygon::get_spin_sides); + ClassDB::bind_method(D_METHOD("set_spin_sides", "spin_sides"), &CSGPolygon3D::set_spin_sides); + ClassDB::bind_method(D_METHOD("get_spin_sides"), &CSGPolygon3D::get_spin_sides); - ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon::set_path_node); - ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon::get_path_node); + 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"), &CSGPolygon::set_path_interval); - ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon::get_path_interval); + ClassDB::bind_method(D_METHOD("set_path_interval", "distance"), &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"), &CSGPolygon::set_path_rotation); - ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon::get_path_rotation); + ClassDB::bind_method(D_METHOD("set_path_rotation", "mode"), &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"), &CSGPolygon::set_path_local); - ClassDB::bind_method(D_METHOD("is_path_local"), &CSGPolygon::is_path_local); + ClassDB::bind_method(D_METHOD("set_path_local", "enable"), &CSGPolygon3D::set_path_local); + ClassDB::bind_method(D_METHOD("is_path_local"), &CSGPolygon3D::is_path_local); - ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon::set_path_continuous_u); - ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon::is_path_continuous_u); + ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon3D::set_path_continuous_u); + ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon3D::is_path_continuous_u); - ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon::set_path_joined); - ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon::is_path_joined); + ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon3D::set_path_joined); + ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon3D::is_path_joined); - ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGPolygon::set_material); - ClassDB::bind_method(D_METHOD("get_material"), &CSGPolygon::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material"), &CSGPolygon3D::set_material); + ClassDB::bind_method(D_METHOD("get_material"), &CSGPolygon3D::get_material); - ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGPolygon::set_smooth_faces); - ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGPolygon::get_smooth_faces); + ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGPolygon3D::set_smooth_faces); + ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGPolygon3D::get_smooth_faces); - ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CSGPolygon::_is_editable_3d_polygon); - ClassDB::bind_method(D_METHOD("_has_editable_3d_polygon_no_depth"), &CSGPolygon::_has_editable_3d_polygon_no_depth); + ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CSGPolygon3D::_is_editable_3d_polygon); + ClassDB::bind_method(D_METHOD("_has_editable_3d_polygon_no_depth"), &CSGPolygon3D::_has_editable_3d_polygon_no_depth); - ClassDB::bind_method(D_METHOD("_path_exited"), &CSGPolygon::_path_exited); - ClassDB::bind_method(D_METHOD("_path_changed"), &CSGPolygon::_path_changed); - - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); + 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::REAL, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); + 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, "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::REAL, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval"); + 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::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, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); BIND_ENUM_CONSTANT(MODE_DEPTH); BIND_ENUM_CONSTANT(MODE_SPIN); @@ -2341,148 +2290,147 @@ void CSGPolygon::_bind_methods() { BIND_ENUM_CONSTANT(PATH_ROTATION_PATH_FOLLOW); } -void CSGPolygon::set_polygon(const Vector<Vector2> &p_polygon) { +void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) { polygon = p_polygon; _make_dirty(); update_gizmo(); } -Vector<Vector2> CSGPolygon::get_polygon() const { +Vector<Vector2> CSGPolygon3D::get_polygon() const { return polygon; } -void CSGPolygon::set_mode(Mode p_mode) { +void CSGPolygon3D::set_mode(Mode p_mode) { mode = p_mode; _make_dirty(); update_gizmo(); _change_notify(); } -CSGPolygon::Mode CSGPolygon::get_mode() const { +CSGPolygon3D::Mode CSGPolygon3D::get_mode() const { return mode; } -void CSGPolygon::set_depth(const float p_depth) { +void CSGPolygon3D::set_depth(const float p_depth) { ERR_FAIL_COND(p_depth < 0.001); depth = p_depth; _make_dirty(); update_gizmo(); } -float CSGPolygon::get_depth() const { +float CSGPolygon3D::get_depth() const { return depth; } -void CSGPolygon::set_path_continuous_u(bool p_enable) { +void CSGPolygon3D::set_path_continuous_u(bool p_enable) { path_continuous_u = p_enable; _make_dirty(); } -bool CSGPolygon::is_path_continuous_u() const { +bool CSGPolygon3D::is_path_continuous_u() const { return path_continuous_u; } -void CSGPolygon::set_spin_degrees(const float p_spin_degrees) { +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(); } -float CSGPolygon::get_spin_degrees() const { +float CSGPolygon3D::get_spin_degrees() const { return spin_degrees; } -void CSGPolygon::set_spin_sides(const int p_spin_sides) { +void CSGPolygon3D::set_spin_sides(const int p_spin_sides) { ERR_FAIL_COND(p_spin_sides < 3); spin_sides = p_spin_sides; _make_dirty(); update_gizmo(); } -int CSGPolygon::get_spin_sides() const { +int CSGPolygon3D::get_spin_sides() const { return spin_sides; } -void CSGPolygon::set_path_node(const NodePath &p_path) { +void CSGPolygon3D::set_path_node(const NodePath &p_path) { path_node = p_path; _make_dirty(); update_gizmo(); } -NodePath CSGPolygon::get_path_node() const { +NodePath CSGPolygon3D::get_path_node() const { return path_node; } -void CSGPolygon::set_path_interval(float p_interval) { +void CSGPolygon3D::set_path_interval(float p_interval) { ERR_FAIL_COND_MSG(p_interval < 0.001, "Path interval cannot be smaller than 0.001."); path_interval = p_interval; _make_dirty(); update_gizmo(); } -float CSGPolygon::get_path_interval() const { + +float CSGPolygon3D::get_path_interval() const { return path_interval; } -void CSGPolygon::set_path_rotation(PathRotation p_rotation) { +void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) { path_rotation = p_rotation; _make_dirty(); update_gizmo(); } -CSGPolygon::PathRotation CSGPolygon::get_path_rotation() const { +CSGPolygon3D::PathRotation CSGPolygon3D::get_path_rotation() const { return path_rotation; } -void CSGPolygon::set_path_local(bool p_enable) { +void CSGPolygon3D::set_path_local(bool p_enable) { path_local = p_enable; _make_dirty(); update_gizmo(); } -bool CSGPolygon::is_path_local() const { +bool CSGPolygon3D::is_path_local() const { return path_local; } -void CSGPolygon::set_path_joined(bool p_enable) { +void CSGPolygon3D::set_path_joined(bool p_enable) { path_joined = p_enable; _make_dirty(); update_gizmo(); } -bool CSGPolygon::is_path_joined() const { +bool CSGPolygon3D::is_path_joined() const { return path_joined; } -void CSGPolygon::set_smooth_faces(const bool p_smooth_faces) { +void CSGPolygon3D::set_smooth_faces(const bool p_smooth_faces) { smooth_faces = p_smooth_faces; _make_dirty(); } -bool CSGPolygon::get_smooth_faces() const { +bool CSGPolygon3D::get_smooth_faces() const { return smooth_faces; } -void CSGPolygon::set_material(const Ref<Material> &p_material) { - +void CSGPolygon3D::set_material(const Ref<Material> &p_material) { material = p_material; _make_dirty(); } -Ref<Material> CSGPolygon::get_material() const { - +Ref<Material> CSGPolygon3D::get_material() const { return material; } -bool CSGPolygon::_is_editable_3d_polygon() const { +bool CSGPolygon3D::_is_editable_3d_polygon() const { return true; } -bool CSGPolygon::_has_editable_3d_polygon_no_depth() const { +bool CSGPolygon3D::_has_editable_3d_polygon_no_depth() const { return true; } -CSGPolygon::CSGPolygon() { +CSGPolygon3D::CSGPolygon3D() { // defaults mode = MODE_DEPTH; polygon.push_back(Vector2(0, 0)); @@ -2498,5 +2446,5 @@ CSGPolygon::CSGPolygon() { path_local = false; path_continuous_u = false; path_joined = false; - path_cache = NULL; + path_cache = nullptr; } diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 6c9419b3c2..7e95d685c5 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,12 +34,12 @@ #define CSGJS_HEADER_ONLY #include "csg.h" -#include "scene/3d/visual_instance.h" -#include "scene/resources/concave_polygon_shape.h" +#include "scene/3d/visual_instance_3d.h" +#include "scene/resources/concave_polygon_shape_3d.h" #include "thirdparty/misc/mikktspace.h" -class CSGShape : public GeometryInstance { - GDCLASS(CSGShape, GeometryInstance); +class CSGShape3D : public GeometryInstance3D { + GDCLASS(CSGShape3D, GeometryInstance3D); public: enum Operation { @@ -51,7 +51,7 @@ public: private: Operation operation; - CSGShape *parent; + CSGShape3D *parent; CSGBrush *brush; @@ -63,7 +63,7 @@ private: bool use_collision; uint32_t collision_layer; uint32_t collision_mask; - Ref<ConcavePolygonShape> root_collision_shape; + Ref<ConcavePolygonShape3D> root_collision_shape; RID root_collision_instance; bool calculate_tangents; @@ -80,17 +80,17 @@ private: }; struct ShapeUpdateSurface { - PoolVector<Vector3> vertices; - PoolVector<Vector3> normals; - PoolVector<Vector2> uvs; - PoolVector<float> tans; + Vector<Vector3> vertices; + Vector<Vector3> normals; + Vector<Vector2> uvs; + Vector<float> tans; Ref<Material> material; int last_added; - PoolVector<Vector3>::Write verticesw; - PoolVector<Vector3>::Write normalsw; - PoolVector<Vector2>::Write uvsw; - PoolVector<float>::Write tansw; + Vector3 *verticesw; + Vector3 *normalsw; + Vector2 *uvsw; + float *tansw; }; //mikktspace callbacks @@ -111,7 +111,7 @@ protected: static void _bind_methods(); - friend class CSGCombiner; + friend class CSGCombiner3D; CSGBrush *_get_brush(); virtual void _validate_property(PropertyInfo &property) const; @@ -122,10 +122,10 @@ public: void set_operation(Operation p_operation); Operation get_operation() const; - virtual PoolVector<Vector3> get_brush_faces(); + virtual Vector<Vector3> get_brush_faces(); virtual AABB get_aabb() const; - virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const; void set_use_collision(bool p_enable); bool is_using_collision() const; @@ -149,41 +149,41 @@ public: bool is_calculating_tangents() const; bool is_root_shape() const; - CSGShape(); - ~CSGShape(); + CSGShape3D(); + ~CSGShape3D(); }; -VARIANT_ENUM_CAST(CSGShape::Operation) +VARIANT_ENUM_CAST(CSGShape3D::Operation) -class CSGCombiner : public CSGShape { - GDCLASS(CSGCombiner, CSGShape); +class CSGCombiner3D : public CSGShape3D { + GDCLASS(CSGCombiner3D, CSGShape3D); private: virtual CSGBrush *_build_brush(); public: - CSGCombiner(); + CSGCombiner3D(); }; -class CSGPrimitive : public CSGShape { - GDCLASS(CSGPrimitive, CSGShape); +class CSGPrimitive3D : public CSGShape3D { + GDCLASS(CSGPrimitive3D, CSGShape3D); private: bool invert_faces; protected: - CSGBrush *_create_brush_from_arrays(const PoolVector<Vector3> &p_vertices, const PoolVector<Vector2> &p_uv, const PoolVector<bool> &p_smooth, const PoolVector<Ref<Material> > &p_materials); + CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials); static void _bind_methods(); public: void set_invert_faces(bool p_invert); bool is_inverting_faces(); - CSGPrimitive(); + CSGPrimitive3D(); }; -class CSGMesh : public CSGPrimitive { - GDCLASS(CSGMesh, CSGPrimitive); +class CSGMesh3D : public CSGPrimitive3D { + GDCLASS(CSGMesh3D, CSGPrimitive3D); virtual CSGBrush *_build_brush(); @@ -203,9 +203,8 @@ public: Ref<Material> get_material() const; }; -class CSGSphere : public CSGPrimitive { - - GDCLASS(CSGSphere, CSGPrimitive); +class CSGSphere3D : public CSGPrimitive3D { + GDCLASS(CSGSphere3D, CSGPrimitive3D); virtual CSGBrush *_build_brush(); Ref<Material> material; @@ -233,12 +232,11 @@ public: void set_smooth_faces(bool p_smooth_faces); bool get_smooth_faces() const; - CSGSphere(); + CSGSphere3D(); }; -class CSGBox : public CSGPrimitive { - - GDCLASS(CSGBox, CSGPrimitive); +class CSGBox3D : public CSGPrimitive3D { + GDCLASS(CSGBox3D, CSGPrimitive3D); virtual CSGBrush *_build_brush(); Ref<Material> material; @@ -262,12 +260,11 @@ public: void set_material(const Ref<Material> &p_material); Ref<Material> get_material() const; - CSGBox(); + CSGBox3D(); }; -class CSGCylinder : public CSGPrimitive { - - GDCLASS(CSGCylinder, CSGPrimitive); +class CSGCylinder3D : public CSGPrimitive3D { + GDCLASS(CSGCylinder3D, CSGPrimitive3D); virtual CSGBrush *_build_brush(); Ref<Material> material; @@ -299,12 +296,11 @@ public: void set_material(const Ref<Material> &p_material); Ref<Material> get_material() const; - CSGCylinder(); + CSGCylinder3D(); }; -class CSGTorus : public CSGPrimitive { - - GDCLASS(CSGTorus, CSGPrimitive); +class CSGTorus3D : public CSGPrimitive3D { + GDCLASS(CSGTorus3D, CSGPrimitive3D); virtual CSGBrush *_build_brush(); Ref<Material> material; @@ -336,12 +332,11 @@ public: void set_material(const Ref<Material> &p_material); Ref<Material> get_material() const; - CSGTorus(); + CSGTorus3D(); }; -class CSGPolygon : public CSGPrimitive { - - GDCLASS(CSGPolygon, CSGPrimitive); +class CSGPolygon3D : public CSGPrimitive3D { + GDCLASS(CSGPolygon3D, CSGPrimitive3D); public: enum Mode { @@ -431,10 +426,10 @@ public: void set_material(const Ref<Material> &p_material); Ref<Material> get_material() const; - CSGPolygon(); + CSGPolygon3D(); }; -VARIANT_ENUM_CAST(CSGPolygon::Mode) -VARIANT_ENUM_CAST(CSGPolygon::PathRotation) +VARIANT_ENUM_CAST(CSGPolygon3D::Mode) +VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation) #endif // CSG_SHAPE_H diff --git a/modules/csg/doc_classes/CSGBox.xml b/modules/csg/doc_classes/CSGBox3D.xml index 14f5a1952e..492bf68c44 100644 --- a/modules/csg/doc_classes/CSGBox.xml +++ b/modules/csg/doc_classes/CSGBox3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGBox" inherits="CSGPrimitive" category="Core" version="3.2"> +<class name="CSGBox3D" inherits="CSGPrimitive3D" version="4.0"> <brief_description> A CSG Box shape. </brief_description> diff --git a/modules/csg/doc_classes/CSGCombiner.xml b/modules/csg/doc_classes/CSGCombiner.xml deleted file mode 100644 index 51428b25f8..0000000000 --- a/modules/csg/doc_classes/CSGCombiner.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGCombiner" inherits="CSGShape" category="Core" version="3.2"> - <brief_description> - A CSG node that allows you to combine other CSG modifiers. - </brief_description> - <description> - For complex arrangements of shapes, it is sometimes needed to add structure to your CSG nodes. The CSGCombiner node allows you to create this structure. The node encapsulates the result of the CSG operations of its children. In this way, it is possible to do operations on one set of shapes that are children of one CSGCombiner node, and a set of separate operations on a second set of shapes that are children of a second CSGCombiner node, and then do an operation that takes the two end results as its input to create the final shape. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml new file mode 100644 index 0000000000..b55111eee4 --- /dev/null +++ b/modules/csg/doc_classes/CSGCombiner3D.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="CSGCombiner3D" inherits="CSGShape3D" version="4.0"> + <brief_description> + A CSG node that allows you to combine other CSG modifiers. + </brief_description> + <description> + For complex arrangements of shapes, it is sometimes needed to add structure to your CSG nodes. The CSGCombiner3D node allows you to create this structure. The node encapsulates the result of the CSG operations of its children. In this way, it is possible to do operations on one set of shapes that are children of one CSGCombiner3D node, and a set of separate operations on a second set of shapes that are children of a second CSGCombiner3D node, and then do an operation that takes the two end results as its input to create the final shape. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/modules/csg/doc_classes/CSGCylinder.xml b/modules/csg/doc_classes/CSGCylinder3D.xml index 9fc0281887..bfd2a5d5f2 100644 --- a/modules/csg/doc_classes/CSGCylinder.xml +++ b/modules/csg/doc_classes/CSGCylinder3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGCylinder" inherits="CSGPrimitive" category="Core" version="3.2"> +<class name="CSGCylinder3D" inherits="CSGPrimitive3D" version="4.0"> <brief_description> A CSG Cylinder shape. </brief_description> diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh3D.xml index afe0bc262d..1bab8f4ee9 100644 --- a/modules/csg/doc_classes/CSGMesh.xml +++ b/modules/csg/doc_classes/CSGMesh3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGMesh" inherits="CSGPrimitive" category="Core" version="3.2"> +<class name="CSGMesh3D" inherits="CSGPrimitive3D" version="4.0"> <brief_description> A CSG Mesh shape that uses a mesh resource. </brief_description> @@ -12,9 +12,10 @@ </methods> <members> <member name="material" type="Material" setter="set_material" getter="get_material"> + The [Material] used in drawing the CSG shape. </member> <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> - The mesh resource to use as a CSG shape. + The [Mesh] resource to use as a CSG shape. </member> </members> <constants> diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index 0ecee92cd5..c55fa0983e 100644 --- a/modules/csg/doc_classes/CSGPolygon.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGPolygon" inherits="CSGPrimitive" category="Core" version="3.2"> +<class name="CSGPolygon3D" inherits="CSGPrimitive3D" version="4.0"> <brief_description> Extrudes a 2D polygon shape to create a 3D mesh. </brief_description> @@ -17,7 +17,7 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> Material to use for the resulting mesh. </member> - <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon.Mode" default="0"> + <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="CSGPolygon3D.Mode" default="0"> Extrusion mode. </member> <member name="path_continuous_u" type="bool" setter="set_path_continuous_u" getter="is_path_continuous_u"> @@ -30,15 +30,15 @@ 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]. </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 CSGPolygon when [member mode] is [constant MODE_PATH]. + 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]. </member> <member name="path_node" type="NodePath" setter="set_path_node" getter="get_path_node"> - The [Shape] object containing the path along which we extrude when [member mode] is [constant MODE_PATH]. + The [Shape3D] object containing the path along which we extrude when [member mode] is [constant MODE_PATH]. </member> - <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon.PathRotation"> + <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]. </member> - <member name="polygon" type="PoolVector2Array" setter="set_polygon" getter="get_polygon" default="PoolVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )"> + <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> <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false"> @@ -53,13 +53,13 @@ </members> <constants> <constant name="MODE_DEPTH" value="0" enum="Mode"> - Shape is extruded to [member depth]. + Shape3D is extruded to [member depth]. </constant> <constant name="MODE_SPIN" value="1" enum="Mode"> - Shape is extruded by rotating it around an axis. + Shape3D is extruded by rotating it around an axis. </constant> <constant name="MODE_PATH" value="2" enum="Mode"> - Shape is extruded along a path set by a [Shape] set in [member path_node]. + Shape3D is extruded along a path set by a [Shape3D] set in [member path_node]. </constant> <constant name="PATH_ROTATION_POLYGON" value="0" enum="PathRotation"> Slice is not rotated. diff --git a/modules/csg/doc_classes/CSGPrimitive.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml index 6c2f837637..31b7360fac 100644 --- a/modules/csg/doc_classes/CSGPrimitive.xml +++ b/modules/csg/doc_classes/CSGPrimitive3D.xml @@ -1,9 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGPrimitive" inherits="CSGShape" category="Core" version="3.2"> +<class name="CSGPrimitive3D" inherits="CSGShape3D" version="4.0"> <brief_description> Base class for CSG primitives. </brief_description> <description> + Parent class for various CSG primitives. It contains code and functionality that is common between them. It cannot be used directly. Instead use one of the various classes that inherit from it. </description> <tutorials> </tutorials> diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape3D.xml index 755d8df67e..43ce988c30 100644 --- a/modules/csg/doc_classes/CSGShape.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGShape" inherits="GeometryInstance" category="Core" version="3.2"> +<class name="CSGShape3D" inherits="GeometryInstance3D" version="4.0"> <brief_description> The CSG base class. </brief_description> @@ -31,6 +31,7 @@ <return type="Array"> </return> <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. </description> </method> <method name="is_root_shape" qualifiers="const"> @@ -75,10 +76,11 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> The physics layers this CSG shape scans for collisions. </member> - <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape.Operation" default="0"> + <member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0"> The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent. </member> <member name="snap" type="float" setter="set_snap" getter="get_snap" default="0.001"> + Snap makes the mesh snap to a given distance so that the faces of two meshes can be perfectly aligned. A lower value results in greater precision but may be harder to adjust. </member> <member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision" default="false"> Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden. diff --git a/modules/csg/doc_classes/CSGSphere.xml b/modules/csg/doc_classes/CSGSphere3D.xml index 714e725acb..4d5b3be099 100644 --- a/modules/csg/doc_classes/CSGSphere.xml +++ b/modules/csg/doc_classes/CSGSphere3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGSphere" inherits="CSGPrimitive" category="Core" version="3.2"> +<class name="CSGSphere3D" inherits="CSGPrimitive3D" version="4.0"> <brief_description> A CSG Sphere shape. </brief_description> diff --git a/modules/csg/doc_classes/CSGTorus.xml b/modules/csg/doc_classes/CSGTorus3D.xml index 5dc6bb8380..abe3eab913 100644 --- a/modules/csg/doc_classes/CSGTorus.xml +++ b/modules/csg/doc_classes/CSGTorus3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CSGTorus" inherits="CSGPrimitive" category="Core" version="3.2"> +<class name="CSGTorus3D" inherits="CSGPrimitive3D" version="4.0"> <brief_description> A CSG Torus shape. </brief_description> diff --git a/modules/csg/icons/icon_c_s_g_box.svg b/modules/csg/icons/CSGBox3D.svg index 67e34df444..67e34df444 100644 --- a/modules/csg/icons/icon_c_s_g_box.svg +++ b/modules/csg/icons/CSGBox3D.svg diff --git a/modules/csg/icons/icon_c_s_g_capsule.svg b/modules/csg/icons/CSGCapsule3D.svg index 92a7b5a870..92a7b5a870 100644 --- a/modules/csg/icons/icon_c_s_g_capsule.svg +++ b/modules/csg/icons/CSGCapsule3D.svg diff --git a/modules/csg/icons/icon_c_s_g_combiner.svg b/modules/csg/icons/CSGCombiner3D.svg index cce2902e24..cce2902e24 100644 --- a/modules/csg/icons/icon_c_s_g_combiner.svg +++ b/modules/csg/icons/CSGCombiner3D.svg diff --git a/modules/csg/icons/icon_c_s_g_cylinder.svg b/modules/csg/icons/CSGCylinder3D.svg index 645a74c79b..645a74c79b 100644 --- a/modules/csg/icons/icon_c_s_g_cylinder.svg +++ b/modules/csg/icons/CSGCylinder3D.svg diff --git a/modules/csg/icons/icon_c_s_g_mesh.svg b/modules/csg/icons/CSGMesh3D.svg index 6e940a4aa5..6e940a4aa5 100644 --- a/modules/csg/icons/icon_c_s_g_mesh.svg +++ b/modules/csg/icons/CSGMesh3D.svg diff --git a/modules/csg/icons/icon_c_s_g_polygon.svg b/modules/csg/icons/CSGPolygon3D.svg index 71b03cb8e6..71b03cb8e6 100644 --- a/modules/csg/icons/icon_c_s_g_polygon.svg +++ b/modules/csg/icons/CSGPolygon3D.svg diff --git a/modules/csg/icons/icon_c_s_g_sphere.svg b/modules/csg/icons/CSGSphere3D.svg index f81b566993..f81b566993 100644 --- a/modules/csg/icons/icon_c_s_g_sphere.svg +++ b/modules/csg/icons/CSGSphere3D.svg diff --git a/modules/csg/icons/icon_c_s_g_torus.svg b/modules/csg/icons/CSGTorus3D.svg index 3d30aa47b2..3d30aa47b2 100644 --- a/modules/csg/icons/icon_c_s_g_torus.svg +++ b/modules/csg/icons/CSGTorus3D.svg diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp index 33e29ec43e..a8bcc2fed1 100644 --- a/modules/csg/register_types.cpp +++ b/modules/csg/register_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,18 +34,17 @@ #include "csg_shape.h" void register_csg_types() { - #ifndef _3D_DISABLED - ClassDB::register_virtual_class<CSGShape>(); - ClassDB::register_virtual_class<CSGPrimitive>(); - ClassDB::register_class<CSGMesh>(); - ClassDB::register_class<CSGSphere>(); - ClassDB::register_class<CSGBox>(); - ClassDB::register_class<CSGCylinder>(); - ClassDB::register_class<CSGTorus>(); - ClassDB::register_class<CSGPolygon>(); - ClassDB::register_class<CSGCombiner>(); + 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>(); #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<EditorPluginCSG>(); diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h index 9e112b72f0..926e598561 100644 --- a/modules/csg/register_types.h +++ b/modules/csg/register_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,5 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef CSG_REGISTER_TYPES_H +#define CSG_REGISTER_TYPES_H + void register_csg_types(); void unregister_csg_types(); + +#endif // CSG_REGISTER_TYPES_H |