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!
This commit is contained in:
parent
b22f048700
commit
8d199a9b2c
18 changed files with 4715 additions and 42 deletions
|
@ -5858,7 +5858,7 @@ EditorNode::EditorNode() {
|
|||
add_editor_plugin(memnew(ParticlesEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(ItemListEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(CollisionPolygonEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(Polygon3DEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(CollisionPolygon2DEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(TileSetEditorPlugin(this)));
|
||||
add_editor_plugin(memnew(TileMapEditorPlugin(this)));
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "scene/3d/camera.h"
|
||||
#include "spatial_editor_plugin.h"
|
||||
|
||||
void CollisionPolygonEditor::_notification(int p_what) {
|
||||
void Polygon3DEditor::_notification(int p_what) {
|
||||
|
||||
switch (p_what) {
|
||||
|
||||
|
@ -53,15 +53,15 @@ void CollisionPolygonEditor::_notification(int p_what) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (node->get_depth() != prev_depth) {
|
||||
if (_get_depth() != prev_depth) {
|
||||
_polygon_draw();
|
||||
prev_depth = node->get_depth();
|
||||
prev_depth = _get_depth();
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
}
|
||||
void CollisionPolygonEditor::_node_removed(Node *p_node) {
|
||||
void Polygon3DEditor::_node_removed(Node *p_node) {
|
||||
|
||||
if (p_node == node) {
|
||||
node = NULL;
|
||||
|
@ -72,7 +72,7 @@ void CollisionPolygonEditor::_node_removed(Node *p_node) {
|
|||
}
|
||||
}
|
||||
|
||||
void CollisionPolygonEditor::_menu_option(int p_option) {
|
||||
void Polygon3DEditor::_menu_option(int p_option) {
|
||||
|
||||
switch (p_option) {
|
||||
|
||||
|
@ -91,10 +91,10 @@ void CollisionPolygonEditor::_menu_option(int p_option) {
|
|||
}
|
||||
}
|
||||
|
||||
void CollisionPolygonEditor::_wip_close() {
|
||||
void Polygon3DEditor::_wip_close() {
|
||||
|
||||
undo_redo->create_action(TTR("Create Poly3D"));
|
||||
undo_redo->add_undo_method(node, "set_polygon", node->get_polygon());
|
||||
undo_redo->add_undo_method(node, "set_polygon", node->call("get_polygon"));
|
||||
undo_redo->add_do_method(node, "set_polygon", wip);
|
||||
undo_redo->add_do_method(this, "_polygon_draw");
|
||||
undo_redo->add_undo_method(this, "_polygon_draw");
|
||||
|
@ -107,14 +107,14 @@ void CollisionPolygonEditor::_wip_close() {
|
|||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
|
||||
bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
|
||||
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
Transform gt = node->get_global_transform();
|
||||
Transform gi = gt.affine_inverse();
|
||||
float depth = node->get_depth() * 0.5;
|
||||
float depth = _get_depth() * 0.5;
|
||||
Vector3 n = gt.basis.get_axis(2).normalized();
|
||||
Plane p(gt.origin + n * depth, n);
|
||||
|
||||
|
@ -137,7 +137,7 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R
|
|||
|
||||
cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint);
|
||||
|
||||
Vector<Vector2> poly = node->get_polygon();
|
||||
Vector<Vector2> poly = node->call("get_polygon");
|
||||
|
||||
//first check if a point is to be added (segment split)
|
||||
real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
|
||||
|
@ -226,7 +226,7 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R
|
|||
poly.insert(closest_idx + 1, cpoint);
|
||||
edited_point = closest_idx + 1;
|
||||
edited_point_pos = cpoint;
|
||||
node->set_polygon(poly);
|
||||
node->call("set_polygon", poly);
|
||||
_polygon_draw();
|
||||
return true;
|
||||
}
|
||||
|
@ -341,7 +341,16 @@ bool CollisionPolygonEditor::forward_spatial_gui_input(Camera *p_camera, const R
|
|||
|
||||
return false;
|
||||
}
|
||||
void CollisionPolygonEditor::_polygon_draw() {
|
||||
|
||||
float Polygon3DEditor::_get_depth() {
|
||||
|
||||
if (bool(node->call("_has_editable_3d_polygon_no_depth")))
|
||||
return 0;
|
||||
|
||||
return float(node->call("get_depth"));
|
||||
}
|
||||
|
||||
void Polygon3DEditor::_polygon_draw() {
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
@ -351,9 +360,9 @@ void CollisionPolygonEditor::_polygon_draw() {
|
|||
if (wip_active)
|
||||
poly = wip;
|
||||
else
|
||||
poly = node->get_polygon();
|
||||
poly = node->call("get_polygon");
|
||||
|
||||
float depth = node->get_depth() * 0.5;
|
||||
float depth = _get_depth() * 0.5;
|
||||
|
||||
imgeom->clear();
|
||||
imgeom->set_material_override(line_material);
|
||||
|
@ -464,13 +473,13 @@ void CollisionPolygonEditor::_polygon_draw() {
|
|||
m->surface_set_material(0, handle_material);
|
||||
}
|
||||
|
||||
void CollisionPolygonEditor::edit(Node *p_collision_polygon) {
|
||||
void Polygon3DEditor::edit(Node *p_collision_polygon) {
|
||||
|
||||
if (p_collision_polygon) {
|
||||
|
||||
node = Object::cast_to<CollisionPolygon>(p_collision_polygon);
|
||||
node = Object::cast_to<Spatial>(p_collision_polygon);
|
||||
//Enable the pencil tool if the polygon is empty
|
||||
if (node->get_polygon().size() == 0) {
|
||||
if (Vector<Vector2>(node->call("get_polygon")).size() == 0) {
|
||||
_menu_option(MODE_CREATE);
|
||||
}
|
||||
wip.clear();
|
||||
|
@ -491,14 +500,14 @@ void CollisionPolygonEditor::edit(Node *p_collision_polygon) {
|
|||
}
|
||||
}
|
||||
|
||||
void CollisionPolygonEditor::_bind_methods() {
|
||||
void Polygon3DEditor::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_menu_option"), &CollisionPolygonEditor::_menu_option);
|
||||
ClassDB::bind_method(D_METHOD("_polygon_draw"), &CollisionPolygonEditor::_polygon_draw);
|
||||
ClassDB::bind_method(D_METHOD("_node_removed"), &CollisionPolygonEditor::_node_removed);
|
||||
ClassDB::bind_method(D_METHOD("_menu_option"), &Polygon3DEditor::_menu_option);
|
||||
ClassDB::bind_method(D_METHOD("_polygon_draw"), &Polygon3DEditor::_polygon_draw);
|
||||
ClassDB::bind_method(D_METHOD("_node_removed"), &Polygon3DEditor::_node_removed);
|
||||
}
|
||||
|
||||
CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) {
|
||||
Polygon3DEditor::Polygon3DEditor(EditorNode *p_editor) {
|
||||
|
||||
node = NULL;
|
||||
editor = p_editor;
|
||||
|
@ -545,22 +554,22 @@ CollisionPolygonEditor::CollisionPolygonEditor(EditorNode *p_editor) {
|
|||
pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
|
||||
}
|
||||
|
||||
CollisionPolygonEditor::~CollisionPolygonEditor() {
|
||||
Polygon3DEditor::~Polygon3DEditor() {
|
||||
|
||||
memdelete(imgeom);
|
||||
}
|
||||
|
||||
void CollisionPolygonEditorPlugin::edit(Object *p_object) {
|
||||
void Polygon3DEditorPlugin::edit(Object *p_object) {
|
||||
|
||||
collision_polygon_editor->edit(Object::cast_to<Node>(p_object));
|
||||
}
|
||||
|
||||
bool CollisionPolygonEditorPlugin::handles(Object *p_object) const {
|
||||
bool Polygon3DEditorPlugin::handles(Object *p_object) const {
|
||||
|
||||
return p_object->is_class("CollisionPolygon");
|
||||
return Object::cast_to<Spatial>(p_object) && bool(p_object->call("_is_editable_3d_polygon"));
|
||||
}
|
||||
|
||||
void CollisionPolygonEditorPlugin::make_visible(bool p_visible) {
|
||||
void Polygon3DEditorPlugin::make_visible(bool p_visible) {
|
||||
|
||||
if (p_visible) {
|
||||
collision_polygon_editor->show();
|
||||
|
@ -571,14 +580,14 @@ void CollisionPolygonEditorPlugin::make_visible(bool p_visible) {
|
|||
}
|
||||
}
|
||||
|
||||
CollisionPolygonEditorPlugin::CollisionPolygonEditorPlugin(EditorNode *p_node) {
|
||||
Polygon3DEditorPlugin::Polygon3DEditorPlugin(EditorNode *p_node) {
|
||||
|
||||
editor = p_node;
|
||||
collision_polygon_editor = memnew(CollisionPolygonEditor(p_node));
|
||||
collision_polygon_editor = memnew(Polygon3DEditor(p_node));
|
||||
SpatialEditor::get_singleton()->add_control_to_menu_panel(collision_polygon_editor);
|
||||
|
||||
collision_polygon_editor->hide();
|
||||
}
|
||||
|
||||
CollisionPolygonEditorPlugin::~CollisionPolygonEditorPlugin() {
|
||||
Polygon3DEditorPlugin::~Polygon3DEditorPlugin() {
|
||||
}
|
||||
|
|
|
@ -44,9 +44,9 @@
|
|||
|
||||
class CanvasItemEditor;
|
||||
|
||||
class CollisionPolygonEditor : public HBoxContainer {
|
||||
class Polygon3DEditor : public HBoxContainer {
|
||||
|
||||
GDCLASS(CollisionPolygonEditor, HBoxContainer);
|
||||
GDCLASS(Polygon3DEditor, HBoxContainer);
|
||||
|
||||
UndoRedo *undo_redo;
|
||||
enum Mode {
|
||||
|
@ -66,7 +66,7 @@ class CollisionPolygonEditor : public HBoxContainer {
|
|||
|
||||
EditorNode *editor;
|
||||
Panel *panel;
|
||||
CollisionPolygon *node;
|
||||
Spatial *node;
|
||||
ImmediateGeometry *imgeom;
|
||||
MeshInstance *pointsm;
|
||||
Ref<ArrayMesh> m;
|
||||
|
@ -85,6 +85,8 @@ class CollisionPolygonEditor : public HBoxContainer {
|
|||
void _polygon_draw();
|
||||
void _menu_option(int p_option);
|
||||
|
||||
float _get_depth();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
void _node_removed(Node *p_node);
|
||||
|
@ -93,28 +95,28 @@ protected:
|
|||
public:
|
||||
virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
|
||||
void edit(Node *p_collision_polygon);
|
||||
CollisionPolygonEditor(EditorNode *p_editor);
|
||||
~CollisionPolygonEditor();
|
||||
Polygon3DEditor(EditorNode *p_editor);
|
||||
~Polygon3DEditor();
|
||||
};
|
||||
|
||||
class CollisionPolygonEditorPlugin : public EditorPlugin {
|
||||
class Polygon3DEditorPlugin : public EditorPlugin {
|
||||
|
||||
GDCLASS(CollisionPolygonEditorPlugin, EditorPlugin);
|
||||
GDCLASS(Polygon3DEditorPlugin, EditorPlugin);
|
||||
|
||||
CollisionPolygonEditor *collision_polygon_editor;
|
||||
Polygon3DEditor *collision_polygon_editor;
|
||||
EditorNode *editor;
|
||||
|
||||
public:
|
||||
virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
|
||||
|
||||
virtual String get_name() const { return "CollisionPolygon"; }
|
||||
virtual String get_name() const { return "Polygon3DEditor"; }
|
||||
bool has_main_screen() const { return false; }
|
||||
virtual void edit(Object *p_object);
|
||||
virtual bool handles(Object *p_object) const;
|
||||
virtual void make_visible(bool p_visible);
|
||||
|
||||
CollisionPolygonEditorPlugin(EditorNode *p_node);
|
||||
~CollisionPolygonEditorPlugin();
|
||||
Polygon3DEditorPlugin(EditorNode *p_node);
|
||||
~Polygon3DEditorPlugin();
|
||||
};
|
||||
|
||||
#endif // COLLISION_POLYGON_EDITOR_PLUGIN_H
|
||||
|
|
9
modules/csg/SCsub
Normal file
9
modules/csg/SCsub
Normal file
|
@ -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")
|
5
modules/csg/config.py
Normal file
5
modules/csg/config.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
def can_build(platform):
|
||||
return True
|
||||
|
||||
def configure(env):
|
||||
pass
|
1472
modules/csg/csg.cpp
Normal file
1472
modules/csg/csg.cpp
Normal file
File diff suppressed because it is too large
Load diff
206
modules/csg/csg.h
Normal file
206
modules/csg/csg.h
Normal file
|
@ -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
|
315
modules/csg/csg_gizmos.cpp
Normal file
315
modules/csg/csg_gizmos.cpp
Normal file
|
@ -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));
|
||||
}
|
30
modules/csg/csg_gizmos.h
Normal file
30
modules/csg/csg_gizmos.h
Normal file
|
@ -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
|
2152
modules/csg/csg_shape.cpp
Normal file
2152
modules/csg/csg_shape.cpp
Normal file
File diff suppressed because it is too large
Load diff
363
modules/csg/csg_shape.h
Normal file
363
modules/csg/csg_shape.h
Normal file
|
@ -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
|
59
modules/csg/register_types.cpp
Normal file
59
modules/csg/register_types.cpp
Normal file
|
@ -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() {
|
||||
|
||||
}
|
32
modules/csg/register_types.h
Normal file
32
modules/csg/register_types.h
Normal file
|
@ -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();
|
|
@ -173,6 +173,9 @@ String CollisionPolygon::get_configuration_warning() const {
|
|||
return String();
|
||||
}
|
||||
|
||||
bool CollisionPolygon::_is_editable_3d_polygon() const {
|
||||
return true;
|
||||
}
|
||||
void CollisionPolygon::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth);
|
||||
|
@ -184,6 +187,8 @@ void CollisionPolygon::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled);
|
||||
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
|
||||
|
|
|
@ -53,6 +53,8 @@ protected:
|
|||
|
||||
void _update_in_shape_owner(bool p_xform_only = false);
|
||||
|
||||
bool _is_editable_3d_polygon() const;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
|
|
@ -40,6 +40,9 @@ void Path::_curve_changed() {
|
|||
|
||||
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
|
||||
update_gizmo();
|
||||
if (is_inside_tree()) {
|
||||
emit_signal("curve_changed");
|
||||
}
|
||||
}
|
||||
|
||||
void Path::set_curve(const Ref<Curve3D> &p_curve) {
|
||||
|
@ -68,6 +71,8 @@ void Path::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("_curve_changed"), &Path::_curve_changed);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("curve_changed"));
|
||||
}
|
||||
|
||||
Path::Path() {
|
||||
|
|
|
@ -912,6 +912,7 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material)
|
|||
VisualServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid());
|
||||
|
||||
_change_notify("material");
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void ArrayMesh::surface_set_name(int p_idx, const String &p_name) {
|
||||
|
@ -919,6 +920,7 @@ void ArrayMesh::surface_set_name(int p_idx, const String &p_name) {
|
|||
ERR_FAIL_INDEX(p_idx, surfaces.size());
|
||||
|
||||
surfaces[p_idx].name = p_name;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
String ArrayMesh::surface_get_name(int p_idx) const {
|
||||
|
@ -931,6 +933,7 @@ void ArrayMesh::surface_update_region(int p_surface, int p_offset, const PoolVec
|
|||
|
||||
ERR_FAIL_INDEX(p_surface, surfaces.size());
|
||||
VS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) {
|
||||
|
@ -938,6 +941,7 @@ void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) {
|
|||
ERR_FAIL_INDEX(p_idx, surfaces.size());
|
||||
surfaces[p_idx].aabb = p_aabb;
|
||||
// set custom aabb too?
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
Ref<Material> ArrayMesh::surface_get_material(int p_idx) const {
|
||||
|
@ -986,6 +990,7 @@ void ArrayMesh::set_custom_aabb(const AABB &p_custom) {
|
|||
|
||||
custom_aabb = p_custom;
|
||||
VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
AABB ArrayMesh::get_custom_aabb() const {
|
||||
|
|
|
@ -65,6 +65,8 @@ void PrimitiveMesh::_update() const {
|
|||
pending_request = false;
|
||||
|
||||
_clear_triangle_mesh();
|
||||
|
||||
const_cast<PrimitiveMesh *>(this)->emit_changed();
|
||||
}
|
||||
|
||||
void PrimitiveMesh::_request_update() {
|
||||
|
|
Loading…
Reference in a new issue