forked from sascha/godot
CSG Support for Godot!
-Missing Icons -Missing freezing option (for baking light and faster load) -Missing a way to export from Godot (GLTF2?) -Probably buggy (may freeze editor, can be worked around easily, but let me know if this happens so it's easier to catch bugs) Happy testing!3.1
parent
b22f048700
commit
8d199a9b2c
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import('env')
|
||||
Import('env_modules')
|
||||
|
||||
env_csg = env_modules.Clone()
|
||||
|
||||
# Godot's own source files
|
||||
env_csg.add_source_files(env.modules_sources, "*.cpp")
|
||||
@ -0,0 +1,5 @@
|
||||
def can_build(platform):
|
||||
return True
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,206 @@
|
||||
#ifndef CSG_H
|
||||
#define CSG_H
|
||||
|
||||
#include "aabb.h"
|
||||
#include "dvector.h"
|
||||
#include "map.h"
|
||||
#include "math_2d.h"
|
||||
#include "oa_hash_map.h"
|
||||
#include "plane.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "transform.h"
|
||||
#include "vector3.h"
|
||||
|
||||
struct CSGBrush {
|
||||
|
||||
struct Face {
|
||||
|
||||
Vector3 vertices[3];
|
||||
Vector2 uvs[3];
|
||||
AABB aabb;
|
||||
bool smooth;
|
||||
bool invert;
|
||||
int material;
|
||||
};
|
||||
|
||||
Vector<Face> faces;
|
||||
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);
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct CSGBrushOperation {
|
||||
|
||||
enum Operation {
|
||||
OPERATION_UNION,
|
||||
OPERATION_INTERSECTION,
|
||||
OPERATION_SUBSTRACTION,
|
||||
|
||||
};
|
||||
|
||||
struct MeshMerge {
|
||||
|
||||
struct BVH {
|
||||
int face;
|
||||
int left;
|
||||
int right;
|
||||
int next;
|
||||
Vector3 center;
|
||||
AABB aabb;
|
||||
};
|
||||
|
||||
struct BVHCmpX {
|
||||
|
||||
bool operator()(const BVH *p_left, const BVH *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 {
|
||||
|
||||
return p_left->center.y < p_right->center.y;
|
||||
}
|
||||
};
|
||||
struct BVHCmpZ {
|
||||
|
||||
bool operator()(const BVH *p_left, const BVH *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 {
|
||||
if (x == p_key.x) {
|
||||
if (y == p_key.y) {
|
||||
return z < p_key.z;
|
||||
} else {
|
||||
return y < p_key.y;
|
||||
}
|
||||
} else {
|
||||
return x < p_key.x;
|
||||
}
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ bool operator==(const VertexKey &p_key) const {
|
||||
return (x == p_key.x && y == p_key.y && z == p_key.z);
|
||||
}
|
||||
};
|
||||
|
||||
struct VertexKeyHash {
|
||||
static _FORCE_INLINE_ uint32_t hash(const VertexKey &p_vk) {
|
||||
uint32_t h = hash_djb2_one_32(p_vk.x);
|
||||
h = hash_djb2_one_32(p_vk.y, h);
|
||||
h = hash_djb2_one_32(p_vk.z, h);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
OAHashMap<VertexKey, int, 64, 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);
|
||||
|
||||
float vertex_snap;
|
||||
void mark_inside_faces();
|
||||
};
|
||||
|
||||
struct BuildPoly {
|
||||
|
||||
Plane plane;
|
||||
Transform to_poly;
|
||||
Transform to_world;
|
||||
int face_index;
|
||||
|
||||
struct Point {
|
||||
Vector2 point;
|
||||
Vector2 uv;
|
||||
};
|
||||
|
||||
Vector<Point> points;
|
||||
|
||||
struct Edge {
|
||||
bool outer;
|
||||
int points[2];
|
||||
Edge() {
|
||||
outer = false;
|
||||
}
|
||||
};
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
#endif // CSG_H
|
||||
@ -0,0 +1,315 @@
|
||||
#include "csg_gizmos.h"
|
||||
|
||||
///////////
|
||||
|
||||
String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const {
|
||||
|
||||
if (Object::cast_to<CSGSphere>(cs)) {
|
||||
|
||||
return "Radius";
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGBox>(cs)) {
|
||||
|
||||
static const char *hname[3] = { "Width", "Height", "Depth" };
|
||||
return hname[p_idx];
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGCylinder>(cs)) {
|
||||
|
||||
return p_idx == 0 ? "Radius" : "Height";
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGTorus>(cs)) {
|
||||
|
||||
return p_idx == 0 ? "InnerRadius" : "OuterRadius";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const {
|
||||
|
||||
if (Object::cast_to<CSGSphere>(cs)) {
|
||||
|
||||
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
|
||||
return s->get_radius();
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGBox>(cs)) {
|
||||
|
||||
CSGBox *s = Object::cast_to<CSGBox>(cs);
|
||||
switch (p_idx) {
|
||||
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);
|
||||
return p_idx == 0 ? s->get_radius() : s->get_height();
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGTorus>(cs)) {
|
||||
|
||||
CSGTorus *s = Object::cast_to<CSGTorus>(cs);
|
||||
return p_idx == 0 ? s->get_inner_radius() : s->get_outer_radius();
|
||||
}
|
||||
|
||||
return Variant();
|
||||
}
|
||||
void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
|
||||
|
||||
Transform gt = cs->get_global_transform();
|
||||
gt.orthonormalize();
|
||||
Transform gi = gt.affine_inverse();
|
||||
|
||||
Vector3 ray_from = p_camera->project_ray_origin(p_point);
|
||||
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
|
||||
|
||||
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);
|
||||
|
||||
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 (d < 0.001)
|
||||
d = 0.001;
|
||||
|
||||
s->set_radius(d);
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGBox>(cs)) {
|
||||
|
||||
CSGBox *s = Object::cast_to<CSGBox>(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 (d < 0.001)
|
||||
d = 0.001;
|
||||
|
||||
switch (p_idx) {
|
||||
case 0: s->set_width(d); break;
|
||||
case 1: s->set_height(d); break;
|
||||
case 2: s->set_depth(d); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGCylinder>(cs)) {
|
||||
|
||||
CSGCylinder *s = Object::cast_to<CSGCylinder>(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 (d < 0.001)
|
||||
d = 0.001;
|
||||
|
||||
if (p_idx == 0)
|
||||
s->set_radius(d);
|
||||
else if (p_idx == 1)
|
||||
s->set_height(d * 2.0);
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGTorus>(cs)) {
|
||||
|
||||
CSGTorus *s = Object::cast_to<CSGTorus>(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 (d < 0.001)
|
||||
d = 0.001;
|
||||
|
||||
if (p_idx == 0)
|
||||
s->set_inner_radius(d);
|
||||
else if (p_idx == 1)
|
||||
s->set_outer_radius(d);
|
||||
}
|
||||
}
|
||||
void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
|
||||
|
||||
if (Object::cast_to<CSGSphere>(cs)) {
|
||||
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
|
||||
if (p_cancel) {
|
||||
s->set_radius(p_restore);
|
||||
return;
|
||||
}
|
||||
|
||||
UndoRedo *ur = SpatialEditor::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 (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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
UndoRedo *ur = SpatialEditor::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;
|
||||
switch (p_idx) {
|
||||
case 0: current = s->get_width(); break;
|
||||
case 1: current = s->get_height(); break;
|
||||
case 2: current = s->get_depth(); break;
|
||||
}
|
||||
|
||||
ur->add_do_method(s, method[p_idx], current);
|
||||
ur->add_undo_method(s, method[p_idx], p_restore);
|
||||
ur->commit_action();
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGCylinder>(cs)) {
|
||||
CSGCylinder *s = Object::cast_to<CSGCylinder>(cs);
|
||||
if (p_cancel) {
|
||||
if (p_idx == 0)
|
||||
s->set_radius(p_restore);
|
||||
else
|
||||
s->set_height(p_restore);
|
||||
return;
|
||||
}
|
||||
|
||||
UndoRedo *ur = SpatialEditor::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());
|
||||
ur->add_undo_method(s, "set_radius", p_restore);
|
||||
} else {
|
||||
ur->create_action(TTR("Change Cylinder Height"));
|
||||
ur->add_do_method(s, "set_height", s->get_height());
|
||||
ur->add_undo_method(s, "set_height", p_restore);
|
||||
}
|
||||
|
||||
ur->commit_action();
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGTorus>(cs)) {
|
||||
CSGTorus *s = Object::cast_to<CSGTorus>(cs);
|
||||
if (p_cancel) {
|
||||
if (p_idx == 0)
|
||||
s->set_inner_radius(p_restore);
|
||||
else
|
||||
s->set_outer_radius(p_restore);
|
||||
return;
|
||||
}
|
||||
|
||||
UndoRedo *ur = SpatialEditor::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());
|
||||
ur->add_undo_method(s, "set_inner_radius", p_restore);
|
||||
} else {
|
||||
ur->create_action(TTR("Change Torus Outer Radius"));
|
||||
ur->add_do_method(s, "set_outer_radius", s->get_outer_radius());
|
||||
ur->add_undo_method(s, "set_outer_radius", p_restore);
|
||||
}
|
||||
|
||||
ur->commit_action();
|
||||
}
|
||||
}
|
||||
void CSGShapeSpatialGizmo::redraw() {
|
||||
|
||||
clear();
|
||||
|
||||
Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/csg");
|
||||
Ref<Material> material = create_material("shape_material", gizmo_color);
|
||||
|
||||
PoolVector<Vector3> faces = cs->get_brush_faces();
|
||||
|
||||
Vector<Vector3> lines;
|
||||
lines.resize(faces.size() * 2);
|
||||
{
|
||||
PoolVector<Vector3>::Read r = faces.read();
|
||||
|
||||
for (int i = 0; i < lines.size(); i += 6) {
|
||||
int f = i / 6;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int j_n = (j + 1) % 3;
|
||||
lines[i + j * 2 + 0] = r[f * 3 + j];
|
||||
lines[i + j * 2 + 1] = r[f * 3 + j_n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_lines(lines, material);
|
||||
add_collision_segments(lines);
|
||||
|
||||
if (Object::cast_to<CSGSphere>(cs)) {
|
||||
CSGSphere *s = Object::cast_to<CSGSphere>(cs);
|
||||
|
||||
float r = s->get_radius();
|
||||
Vector<Vector3> handles;
|
||||
handles.push_back(Vector3(r, 0, 0));
|
||||
add_handles(handles);
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGBox>(cs)) {
|
||||
CSGBox *s = Object::cast_to<CSGBox>(cs);
|
||||
|
||||
Vector<Vector3> handles;
|
||||
handles.push_back(Vector3(s->get_width(), 0, 0));
|
||||
handles.push_back(Vector3(0, s->get_height(), 0));
|
||||
handles.push_back(Vector3(0, 0, s->get_depth()));
|
||||
add_handles(handles);
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGCylinder>(cs)) {
|
||||
CSGCylinder *s = Object::cast_to<CSGCylinder>(cs);
|
||||
|
||||
Vector<Vector3> handles;
|
||||
handles.push_back(Vector3(s->get_radius(), 0, 0));
|
||||
handles.push_back(Vector3(0, s->get_height() * 0.5, 0));
|
||||
add_handles(handles);
|
||||
}
|
||||
|
||||
if (Object::cast_to<CSGTorus>(cs)) {
|
||||
CSGTorus *s = Object::cast_to<CSGTorus>(cs);
|
||||
|
||||
Vector<Vector3> handles;
|
||||
handles.push_back(Vector3(s->get_inner_radius(), 0, 0));
|
||||
handles.push_back(Vector3(s->get_outer_radius(), 0, 0));
|
||||
add_handles(handles);
|
||||
}
|
||||
}
|
||||
CSGShapeSpatialGizmo::CSGShapeSpatialGizmo(CSGShape *p_cs) {
|
||||
|
||||
cs = p_cs;
|
||||
set_spatial_node(p_cs);
|
||||
}
|
||||
|
||||
Ref<SpatialEditorGizmo> EditorPluginCSG::create_spatial_gizmo(Spatial *p_spatial) {
|
||||
if (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)) {
|
||||
Ref<CSGShapeSpatialGizmo> csg = memnew(CSGShapeSpatialGizmo(Object::cast_to<CSGShape>(p_spatial)));
|
||||
return csg;
|
||||
}
|
||||
|
||||
return Ref<SpatialEditorGizmo>();
|
||||
}
|
||||
|
||||
EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) {
|
||||
|
||||
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1));
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
#ifndef CSG_GIZMOS_H
|
||||
#define CSG_GIZMOS_H
|
||||
|
||||
#include "csg_shape.h"
|
||||
#include "editor/editor_plugin.h"
|
||||
#include "editor/spatial_editor_gizmos.h"
|
||||
|
||||
class CSGShapeSpatialGizmo : public EditorSpatialGizmo {
|
||||
|
||||
GDCLASS(CSGShapeSpatialGizmo, EditorSpatialGizmo);
|
||||
|
||||
CSGShape *cs;
|
||||
|
||||
public:
|
||||
virtual String get_handle_name(int p_idx) const;
|
||||
virtual Variant get_handle_value(int p_idx) const;
|
||||
virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point);
|
||||
virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false);
|
||||
void redraw();
|
||||
CSGShapeSpatialGizmo(CSGShape *p_cs = NULL);
|
||||
};
|
||||
|
||||
class EditorPluginCSG : public EditorPlugin {
|
||||
GDCLASS(EditorPluginCSG, EditorPlugin)
|
||||
public:
|
||||
virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
|
||||
EditorPluginCSG(EditorNode *p_editor);
|
||||
};
|
||||
|
||||
#endif // CSG_GIZMOS_H
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,363 @@
|
||||
#ifndef CSG_SHAPE_H
|
||||
#define CSG_SHAPE_H
|
||||
|
||||
#define CSGJS_HEADER_ONLY
|
||||
|
||||
#include "csg.h"
|
||||
#include "scene/3d/visual_instance.h"
|
||||
#include "scene/resources/concave_polygon_shape.h"
|
||||
|
||||
class CSGShape : public VisualInstance {
|
||||
GDCLASS(CSGShape, VisualInstance);
|
||||
|
||||
public:
|
||||
enum Operation {
|
||||
OPERATION_UNION,
|
||||
OPERATION_INTERSECTION,
|
||||
OPERATION_SUBTRACTION,
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
Operation operation;
|
||||
CSGShape *parent;
|
||||
|
||||
CSGBrush *brush;
|
||||
|
||||
AABB node_aabb;
|
||||
|
||||
bool dirty;
|
||||
|
||||
bool use_collision;
|
||||
Ref<ConcavePolygonShape> root_collision_shape;
|
||||
RID root_collision_instance;
|
||||
|
||||
Ref<ArrayMesh> root_mesh;
|
||||
|
||||
struct Vector3Hasher {
|
||||
_ALWAYS_INLINE_ uint32_t hash(const Vector3 &p_vec3) const {
|
||||
uint32_t h = hash_djb2_one_float(p_vec3.x);
|
||||
h = hash_djb2_one_float(p_vec3.y, h);
|
||||
h = hash_djb2_one_float(p_vec3.z, h);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct ShapeUpdateSurface {
|
||||
PoolVector<Vector3> vertices;
|
||||
PoolVector<Vector3> normals;
|
||||
PoolVector<Vector2> uvs;
|
||||
Ref<Material> material;
|
||||
int last_added;
|
||||
|
||||
PoolVector<Vector3>::Write verticesw;
|
||||
PoolVector<Vector3>::Write normalsw;
|
||||
PoolVector<Vector2>::Write uvsw;
|
||||
};
|
||||
|
||||
void _update_shape();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb) = 0;
|
||||
void _make_dirty();
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
friend class CSGCombiner;
|
||||
CSGBrush *_get_brush();
|
||||
|
||||
virtual void _validate_property(PropertyInfo &property) const;
|
||||
|
||||
public:
|
||||
void set_operation(Operation p_operation);
|
||||
Operation get_operation() const;
|
||||
|
||||
virtual PoolVector<Vector3> get_brush_faces();
|
||||
|
||||
virtual AABB get_aabb() const;
|
||||
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
|
||||
|
||||
void set_use_collision(bool p_enable);
|
||||
bool is_using_collision() const;
|
||||
|
||||
bool is_root_shape() const;
|
||||
CSGShape();
|
||||
~CSGShape();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(CSGShape::Operation)
|
||||
|
||||
class CSGCombiner : public CSGShape {
|
||||
GDCLASS(CSGCombiner, CSGShape)
|
||||
private:
|
||||
float snap;
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_snap(float p_snap);
|
||||
float get_snap() const;
|
||||
|
||||
CSGCombiner();
|
||||
};
|
||||
|
||||
class CSGPrimitive : public CSGShape {
|
||||
GDCLASS(CSGPrimitive, CSGShape)
|
||||
|
||||
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);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_invert_faces(bool p_invert);
|
||||
bool is_inverting_faces();
|
||||
|
||||
CSGPrimitive();
|
||||
};
|
||||
|
||||
class CSGMesh : public CSGPrimitive {
|
||||
GDCLASS(CSGMesh, CSGPrimitive)
|
||||
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
Ref<Mesh> mesh;
|
||||
|
||||
void _mesh_changed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_mesh(const Ref<Mesh> &p_mesh);
|
||||
Ref<Mesh> get_mesh();
|
||||
};
|
||||
|
||||
class CSGSphere : public CSGPrimitive {
|
||||
|
||||
GDCLASS(CSGSphere, CSGPrimitive)
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
Ref<Material> material;
|
||||
bool smooth_faces;
|
||||
float radius;
|
||||
int radial_segments;
|
||||
int rings;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_radius(const float p_radius);
|
||||
float get_radius() const;
|
||||
|
||||
void set_radial_segments(const int p_radial_segments);
|
||||
int get_radial_segments() const;
|
||||
|
||||
void set_rings(const int p_rings);
|
||||
int get_rings() const;
|
||||
|
||||
void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
void set_smooth_faces(bool p_smooth_faces);
|
||||
bool get_smooth_faces() const;
|
||||
|
||||
CSGSphere();
|
||||
};
|
||||
|
||||
class CSGBox : public CSGPrimitive {
|
||||
|
||||
GDCLASS(CSGBox, CSGPrimitive)
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
Ref<Material> material;
|
||||
float width;
|
||||
float height;
|
||||
float depth;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_width(const float p_width);
|
||||
float get_width() const;
|
||||
|
||||
void set_height(const float p_height);
|
||||
float get_height() const;
|
||||
|
||||
void set_depth(const float p_depth);
|
||||
float get_depth() const;
|
||||
|
||||
void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
CSGBox();
|
||||
};
|
||||
|
||||
class CSGCylinder : public CSGPrimitive {
|
||||
|
||||
GDCLASS(CSGCylinder, CSGPrimitive)
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
Ref<Material> material;
|
||||
float radius;
|
||||
float height;
|
||||
int sides;
|
||||
bool cone;
|
||||
bool smooth_faces;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_radius(const float p_radius);
|
||||
float get_radius() const;
|
||||
|
||||
void set_height(const float p_height);
|
||||
float get_height() const;
|
||||
|
||||
void set_sides(const int p_sides);
|
||||
int get_sides() const;
|
||||
|
||||
void set_cone(const bool p_cone);
|
||||
bool is_cone() const;
|
||||
|
||||
void set_smooth_faces(bool p_smooth_faces);
|
||||
bool get_smooth_faces() const;
|
||||
|
||||
void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
CSGCylinder();
|
||||
};
|
||||
|
||||
class CSGTorus : public CSGPrimitive {
|
||||
|
||||
GDCLASS(CSGTorus, CSGPrimitive)
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
Ref<Material> material;
|
||||
float inner_radius;
|
||||
float outer_radius;
|
||||
int sides;
|
||||
int ring_sides;
|
||||
bool smooth_faces;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_inner_radius(const float p_inner_radius);
|
||||
float get_inner_radius() const;
|
||||
|
||||
void set_outer_radius(const float p_outer_radius);
|
||||
float get_outer_radius() const;
|
||||
|
||||
void set_sides(const int p_sides);
|
||||
int get_sides() const;
|
||||
|
||||
void set_ring_sides(const int p_ring_sides);
|
||||
int get_ring_sides() const;
|
||||
|
||||
void set_smooth_faces(bool p_smooth_faces);
|
||||
bool get_smooth_faces() const;
|
||||
|
||||
void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
CSGTorus();
|
||||
};
|
||||
|
||||
class CSGPolygon : public CSGPrimitive {
|
||||
|
||||
GDCLASS(CSGPolygon, CSGPrimitive)
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
MODE_DEPTH,
|
||||
MODE_SPIN,
|
||||
MODE_PATH
|
||||
};
|
||||
|
||||
enum PathRotation {
|
||||
PATH_ROTATION_POLYGON,
|
||||
PATH_ROTATION_PATH,
|
||||
PATH_ROTATION_PATH_FOLLOW,
|
||||
};
|
||||
|
||||
private:
|
||||
virtual CSGBrush *_build_brush(AABB *r_aabb);
|
||||
|
||||
Vector<Vector2> polygon;
|
||||
Ref<Material> material;
|
||||
|
||||
Mode mode;
|
||||
|
||||
float depth;
|
||||
|
||||
float spin_degrees;
|
||||
int spin_sides;
|
||||
|
||||
NodePath path_node;
|
||||
float path_interval;
|
||||
PathRotation path_rotation;
|
||||
|
||||
Node *path_cache;
|
||||
|
||||
bool smooth_faces;
|
||||
|
||||
bool _is_editable_3d_polygon() const;
|
||||
bool _has_editable_3d_polygon_no_depth() const;
|
||||
|
||||
void _path_changed();
|
||||
void _path_exited();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
virtual void _validate_property(PropertyInfo &property) const;
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
void set_polygon(const Vector<Vector2> &p_polygon);
|
||||
Vector<Vector2> get_polygon() const;
|
||||
|
||||
void set_mode(Mode p_mode);
|
||||
Mode get_mode() const;
|
||||
|
||||
void set_depth(float p_depth);
|
||||
float get_depth() const;
|
||||
|
||||
void set_spin_degrees(float p_spin_degrees);
|
||||
float get_spin_degrees() const;
|
||||
|
||||
void set_spin_sides(int p_sides);
|
||||
int get_spin_sides() const;
|
||||
|
||||
void set_path_node(const NodePath &p_path);
|
||||
NodePath get_path_node() const;
|
||||
|
||||
void set_path_interval(float p_interval);
|
||||
float get_path_interval() const;
|
||||
|
||||
void set_path_rotation(PathRotation p_rotation);
|
||||
PathRotation get_path_rotation() const;
|
||||
|
||||
void set_smooth_faces(bool p_smooth_faces);
|
||||
bool get_smooth_faces() const;
|
||||
|
||||
void set_material(const Ref<Material> &p_material);
|
||||
Ref<Material> get_material() const;
|
||||
|
||||
CSGPolygon();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(CSGPolygon::Mode)
|
||||
VARIANT_ENUM_CAST(CSGPolygon::PathRotation)
|
||||
|
||||
#endif // CSG_SHAPE_H
|
||||
@ -0,0 +1,59 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "csg_shape.h"
|
||||
#include "csg_gizmos.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>();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
EditorPlugins::add_by_type<EditorPluginCSG>();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void unregister_csg_types() {
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2018 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
void register_csg_types();
|
||||
void unregister_csg_types();
|
||||
Loading…
Reference in New Issue