summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp1
-rw-r--r--scene/2d/canvas_item.cpp21
-rw-r--r--scene/2d/collision_shape_2d.cpp2
-rw-r--r--scene/2d/navigation2d.cpp11
-rw-r--r--scene/2d/navigation_polygon.cpp2
-rw-r--r--scene/2d/physics_body_2d.cpp55
-rw-r--r--scene/2d/physics_body_2d.h4
-rw-r--r--scene/2d/polygon_2d.cpp3
-rw-r--r--scene/2d/ray_cast_2d.cpp34
-rw-r--r--scene/2d/ray_cast_2d.h9
-rw-r--r--scene/2d/remote_transform_2d.cpp7
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/sprite.cpp38
-rw-r--r--scene/2d/sprite.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp1
-rw-r--r--scene/3d/baked_lightmap.cpp3
-rw-r--r--scene/3d/camera.cpp252
-rw-r--r--scene/3d/camera.h60
-rw-r--r--scene/3d/cpu_particles.cpp2
-rw-r--r--scene/3d/navigation.cpp9
-rw-r--r--scene/3d/physics_body.cpp193
-rw-r--r--scene/3d/physics_body.h11
-rw-r--r--scene/3d/ray_cast.cpp34
-rw-r--r--scene/3d/ray_cast.h10
-rw-r--r--scene/3d/remote_transform.cpp4
-rw-r--r--scene/3d/spring_arm.cpp172
-rw-r--r--scene/3d/spring_arm.h71
-rw-r--r--scene/3d/vehicle_body.cpp10
-rw-r--r--scene/3d/voxel_light_baker.cpp26
-rw-r--r--scene/animation/animation_blend_space_1d.cpp77
-rw-r--r--scene/animation/animation_blend_space_1d.h17
-rw-r--r--scene/animation/animation_blend_space_2d.cpp69
-rw-r--r--scene/animation/animation_blend_space_2d.h15
-rw-r--r--scene/animation/animation_blend_tree.cpp520
-rw-r--r--scene/animation/animation_blend_tree.h112
-rw-r--r--scene/animation/animation_node_state_machine.cpp837
-rw-r--r--scene/animation/animation_node_state_machine.h109
-rw-r--r--scene/animation/animation_player.cpp2
-rw-r--r--scene/animation/animation_tree.cpp361
-rw-r--r--scene/animation/animation_tree.h66
-rw-r--r--scene/animation/skeleton_ik.cpp4
-rw-r--r--scene/animation/skeleton_ik.h4
-rw-r--r--scene/audio/audio_player.cpp1
-rw-r--r--scene/gui/base_button.cpp2
-rw-r--r--scene/gui/button.cpp3
-rw-r--r--scene/gui/control.cpp3
-rw-r--r--scene/gui/file_dialog.cpp3
-rw-r--r--scene/gui/gradient_edit.cpp1
-rw-r--r--scene/gui/graph_edit.cpp63
-rw-r--r--scene/gui/graph_edit.h4
-rw-r--r--scene/gui/item_list.cpp3
-rw-r--r--scene/gui/link_button.cpp2
-rw-r--r--scene/gui/rich_text_label.cpp1
-rw-r--r--scene/gui/text_edit.cpp4
-rw-r--r--scene/main/node.cpp12
-rw-r--r--scene/main/scene_tree.cpp2
-rw-r--r--scene/main/viewport.cpp31
-rw-r--r--scene/main/viewport.h3
-rw-r--r--scene/register_scene_types.cpp13
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/bit_mask.cpp16
-rw-r--r--scene/resources/dynamic_font.cpp2
-rw-r--r--scene/resources/dynamic_font_stb.cpp5
-rw-r--r--scene/resources/material.cpp76
-rw-r--r--scene/resources/material.h18
-rw-r--r--scene/resources/mesh.cpp4
-rw-r--r--scene/resources/packed_scene.cpp13
-rw-r--r--scene/resources/physics_material.h2
-rw-r--r--scene/resources/shader_graph.cpp2596
-rw-r--r--scene/resources/shader_graph.h446
-rw-r--r--scene/resources/shape.cpp23
-rw-r--r--scene/resources/shape.h6
-rw-r--r--scene/resources/surface_tool.cpp10
-rw-r--r--scene/resources/texture.cpp149
-rw-r--r--scene/resources/texture.h19
-rw-r--r--scene/resources/visual_shader.cpp2
-rw-r--r--scene/scene_string_names.cpp2
-rw-r--r--scene/scene_string_names.h2
78 files changed, 2542 insertions, 4244 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 507499a324..559e041dbf 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -296,6 +296,7 @@ float AudioStreamPlayer2D::get_volume_db() const {
}
void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {
+ ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
}
float AudioStreamPlayer2D::get_pitch_scale() const {
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index a035d9021f..7f7e3542ed 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -349,23 +349,12 @@ void CanvasItem::_update_callback() {
Transform2D CanvasItem::get_global_transform_with_canvas() const {
- const CanvasItem *ci = this;
- Transform2D xform;
- const CanvasItem *last_valid = NULL;
-
- while (ci) {
-
- last_valid = ci;
- xform = ci->get_transform() * xform;
- ci = ci->get_parent_item();
- }
-
- if (last_valid->canvas_layer)
- return last_valid->canvas_layer->get_transform() * xform;
+ if (canvas_layer)
+ return canvas_layer->get_transform() * get_global_transform();
else if (is_inside_tree())
- return get_viewport()->get_canvas_transform() * xform;
-
- return xform;
+ return get_viewport()->get_canvas_transform() * get_global_transform();
+ else
+ return get_global_transform();
}
Transform2D CanvasItem::get_global_transform() const {
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 83ef4df8f4..ff5f7062c4 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -119,7 +119,7 @@ void CollisionShape2D::_notification(int p_what) {
Color draw_col = get_tree()->get_debug_collisions_color();
if (disabled) {
- float g = draw_col.gray();
+ float g = draw_col.get_v();
draw_col.r = g;
draw_col.g = g;
draw_col.b = g;
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index e3b048fd74..9eec8e6cc3 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -121,7 +121,6 @@ void Navigation2D::_navpoly_link(int p_id) {
pending.edge = j;
p.edges.write[j].P = C->get().pending.push_back(pending);
continue;
- //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
}
C->get().B = &p;
@@ -144,8 +143,6 @@ void Navigation2D::_navpoly_unlink(int p_id) {
NavMesh &nm = navpoly_map[p_id];
ERR_FAIL_COND(!nm.linked);
- //print_line("UNLINK");
-
for (List<Polygon>::Element *E = nm.polygons.front(); E; E = E->next()) {
Polygon &p = E->get();
@@ -341,7 +338,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
path.resize(2);
path.write[0] = begin_point;
path.write[1] = end_point;
- //print_line("Direct Path");
return path;
}
@@ -379,7 +375,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
while (!found_route) {
if (open_list.size() == 0) {
- //print_line("NOU OPEN LIST");
break;
}
//check open list
@@ -526,7 +521,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (portal_left.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
left_poly = p;
portal_left = left;
- //print_line("***ADVANCE LEFT");
} else {
apex_point = portal_right;
@@ -537,8 +531,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON)
path.push_back(apex_point);
skip = true;
- //print_line("addpoint left");
- //print_line("***CLIP LEFT");
}
}
@@ -547,7 +539,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
if (portal_right.distance_squared_to(apex_point) < CMP_EPSILON || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
right_poly = p;
portal_right = right;
- //print_line("***ADVANCE RIGHT");
} else {
apex_point = portal_left;
@@ -557,8 +548,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
portal_left = apex_point;
if (!path.size() || path[path.size() - 1].distance_to(apex_point) > CMP_EPSILON)
path.push_back(apex_point);
- //print_line("addpoint right");
- //print_line("***CLIP RIGHT");
}
}
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index 2d6679272a..84b12b0bfe 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -257,7 +257,7 @@ void NavigationPolygon::make_polygons_from_outlines() {
TriangulatorPartition tpart;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- print_line("convex partition failed!");
+ ERR_PRINTS("NavigationPolygon: Convex partition failed!");
return;
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 8758ffef9f..8e31688d90 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -365,13 +365,6 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
- /*if (obj) {
- if (body_in)
- print_line("in: "+String(obj->call("get_name")));
- else
- print_line("out: "+String(obj->call("get_name")));
- }*/
-
ERR_FAIL_COND(!body_in && !E);
if (body_in) {
@@ -1207,7 +1200,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
-Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
+Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) {
Vector2 floor_motion = floor_velocity;
if (on_floor && on_floor_body.is_valid()) {
@@ -1228,6 +1221,8 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
colliders.clear();
floor_velocity = Vector2();
+ Vector2 lv_n = p_linear_velocity.normalized();
+
while (p_max_slides) {
Collision collision;
@@ -1254,8 +1249,10 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
if (collided) {
+ colliders.push_back(collision);
motion = collision.remainder;
+ bool is_on_slope = false;
if (p_floor_direction == Vector2()) {
//all is a wall
on_wall = true;
@@ -1266,15 +1263,17 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
on_floor_body = collision.collider_rid;
floor_velocity = collision.collider_vel;
- Vector2 rel_v = lv - floor_velocity;
- Vector2 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v);
-
- if (collision.travel.length() < 1 && hv.length() < p_slope_stop_min_velocity) {
- Transform2D gt = get_global_transform();
- gt.elements[2] -= collision.travel;
- set_global_transform(gt);
- return Vector2();
+ if (p_stop_on_slope) {
+ if (Vector2() == lv_n + p_floor_direction) {
+ Transform2D gt = get_global_transform();
+ gt.elements[2] -= collision.travel;
+ set_global_transform(gt);
+ return Vector2();
+ }
}
+
+ is_on_slope = true;
+
} else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
on_ceiling = true;
} else {
@@ -1282,12 +1281,18 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
}
}
- Vector2 n = collision.normal;
- motion = motion.slide(n);
- lv = lv.slide(n);
-
- colliders.push_back(collision);
+ if (p_stop_on_slope && is_on_slope) {
+ motion = motion.slide(p_floor_direction);
+ lv = lv.slide(p_floor_direction);
+ } else {
+ Vector2 n = collision.normal;
+ motion = motion.slide(n);
+ lv = lv.slide(n);
+ }
}
+
+ if (p_stop_on_slope)
+ break;
}
if (!found_collision) {
@@ -1301,11 +1306,11 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
return lv;
}
-Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
+Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) {
bool was_on_floor = on_floor;
- Vector2 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_infinite_inertia, p_slope_stop_min_velocity, p_max_slides, p_floor_max_angle);
+ Vector2 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_infinite_inertia, p_stop_on_slope, p_max_slides, p_floor_max_angle);
if (!was_on_floor || p_snap == Vector2()) {
return ret;
}
@@ -1439,8 +1444,8 @@ void KinematicBody2D::_notification(int p_what) {
void KinematicBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
- ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 0a2ce0918b..852963a721 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -338,8 +338,8 @@ public:
void set_safe_margin(float p_margin);
float get_safe_margin() const;
- Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 5, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
- Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 5, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
+ Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
+ Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 34f4ccc03e..fc0741cc5c 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -253,7 +253,6 @@ void Polygon2D::_notification(int p_what) {
//normalize
for (int j = 0; j < 4; j++) {
weightsw[i * 4 + j] /= tw;
- // print_line("point " + itos(i) + " idx " + itos(j) + " index: " + itos(bonesw[i * 4 + j]) + " weight: " + rtos(weightsw[i * 4 + j]));
}
}
}
@@ -345,8 +344,6 @@ void Polygon2D::_notification(int p_what) {
}
}
- //print_line("loops: " + itos(loops.size()) + " indices: " + itos(indices.size()));
-
VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
}
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 255d2d38d5..9582c08110 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -209,7 +209,7 @@ void RayCast2D::_update_raycast_state() {
Physics2DDirectSpaceState::RayResult rr;
- if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask)) {
+ if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
collided = true;
against = rr.collider_id;
@@ -258,6 +258,26 @@ void RayCast2D::clear_exceptions() {
exclude.clear();
}
+void RayCast2D::set_collide_with_areas(bool p_clip) {
+
+ collide_with_areas = p_clip;
+}
+
+bool RayCast2D::is_collide_with_areas_enabled() const {
+
+ return collide_with_areas;
+}
+
+void RayCast2D::set_collide_with_bodies(bool p_clip) {
+
+ collide_with_bodies = p_clip;
+}
+
+bool RayCast2D::is_collide_with_bodies_enabled() const {
+
+ return collide_with_bodies;
+}
+
void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast2D::set_enabled);
@@ -291,10 +311,20 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast2D::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast2D::get_exclude_parent_body);
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast2D::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast2D::is_collide_with_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast2D::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast2D::is_collide_with_bodies_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cast_to"), "set_cast_to", "get_cast_to");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Collide With", "collide_with");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
}
RayCast2D::RayCast2D() {
@@ -306,4 +336,6 @@ RayCast2D::RayCast2D() {
collision_mask = 1;
cast_to = Vector2(0, 50);
exclude_parent_body = true;
+ collide_with_bodies = true;
+ collide_with_areas = false;
}
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 0850cdc7cc..a438be87b6 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -49,12 +49,21 @@ class RayCast2D : public Node2D {
Vector2 cast_to;
+ bool collide_with_areas;
+ bool collide_with_bodies;
+
protected:
void _notification(int p_what);
void _update_raycast_state();
static void _bind_methods();
public:
+ void set_collide_with_areas(bool p_clip);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_collide_with_bodies(bool p_clip);
+ bool is_collide_with_bodies_enabled() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index 63c3d78dfd..f0274e5206 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -67,7 +67,7 @@ void RemoteTransform2D::_update_remote() {
} else {
Transform2D n_trans = n->get_global_transform();
Transform2D our_trans = get_global_transform();
- Vector2 n_scale = n->get_global_scale();
+ Vector2 n_scale = n->get_scale();
if (!update_remote_position)
our_trans.set_origin(n_trans.get_origin());
@@ -131,8 +131,10 @@ void RemoteTransform2D::_notification(int p_what) {
void RemoteTransform2D::set_remote_node(const NodePath &p_remote_node) {
remote_node = p_remote_node;
- if (is_inside_tree())
+ if (is_inside_tree()) {
_update_cache();
+ _update_remote();
+ }
update_configuration_warning();
}
@@ -144,6 +146,7 @@ NodePath RemoteTransform2D::get_remote_node() const {
void RemoteTransform2D::set_use_global_coordinates(const bool p_enable) {
use_global_coordinates = p_enable;
+ _update_remote();
}
bool RemoteTransform2D::get_use_global_coordinates() const {
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index e6e9bde20a..2c362f1b31 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -288,7 +288,7 @@ void Skeleton2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);
ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count);
- ClassDB::bind_method(D_METHOD("get_bone"), &Skeleton2D::get_bone);
+ ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone);
ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
}
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index ebe0e81f6e..bb5990fa79 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -298,6 +298,11 @@ int Sprite::get_hframes() const {
bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ return is_pixel_opaque(p_point);
+}
+
+bool Sprite::is_pixel_opaque(const Point2 &p_point) const {
+
if (texture.is_null())
return false;
@@ -316,32 +321,6 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
q.y = 1.0f - q.y;
q = q * src_rect.size + src_rect.position;
- Ref<Image> image;
- Ref<AtlasTexture> atlasTexture = texture;
- if (atlasTexture.is_null()) {
- image = texture->get_data();
- } else {
- ERR_FAIL_COND_V(atlasTexture->get_atlas().is_null(), false);
-
- image = atlasTexture->get_atlas()->get_data();
-
- Rect2 region = atlasTexture->get_region();
- Rect2 margin = atlasTexture->get_margin();
-
- q -= margin.position;
-
- if ((q.x > region.size.width) || (q.y > region.size.height)) {
- return false;
- }
-
- q += region.position;
- }
-
- ERR_FAIL_COND_V(image.is_null(), false);
- if (image->is_compressed()) {
- return dst_rect.has_point(p_point);
- }
-
bool is_repeat = texture->get_flags() & Texture::FLAG_REPEAT;
bool is_mirrored_repeat = texture->get_flags() & Texture::FLAG_MIRRORED_REPEAT;
if (is_repeat) {
@@ -363,11 +342,8 @@ bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
q.x = MIN(q.x, texture->get_size().width - 1);
q.y = MIN(q.y, texture->get_size().height - 1);
}
- image->lock();
- const Color c = image->get_pixel((int)q.x, (int)q.y);
- image->unlock();
- return c.a > 0.01;
+ return texture->is_pixel_opaque((int)q.x, (int)q.y);
}
Rect2 Sprite::get_rect() const {
@@ -437,6 +413,8 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite::set_region);
ClassDB::bind_method(D_METHOD("is_region"), &Sprite::is_region);
+ ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite::is_pixel_opaque);
+
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect);
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index 0a5ff002cd..ab444f89fc 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -75,6 +75,8 @@ public:
virtual bool _edit_use_pivot() const;
virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+ bool is_pixel_opaque(const Point2 &p_point) const;
+
virtual Rect2 _edit_get_rect() const;
virtual bool _edit_use_rect() const;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 5f0ac3dd80..8504a18f54 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -626,6 +626,7 @@ float AudioStreamPlayer3D::get_max_db() const {
}
void AudioStreamPlayer3D::set_pitch_scale(float p_pitch_scale) {
+ ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
}
float AudioStreamPlayer3D::get_pitch_scale() const {
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 26fd5ed658..2cb59c871c 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -374,9 +374,6 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
capture_subdiv--;
css *= 2.0;
}
-
- print_line("bake subdiv: " + itos(bake_subdiv));
- print_line("capture subdiv: " + itos(capture_subdiv));
}
baker.begin_bake(bake_subdiv, bake_bounds);
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index 2176b45faf..a4582b7d7d 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -31,9 +31,10 @@
#include "camera.h"
#include "camera_matrix.h"
+#include "collision_object.h"
+#include "engine.h"
#include "scene/resources/material.h"
#include "scene/resources/surface_tool.h"
-
void Camera::_update_audio_listener_state() {
}
@@ -313,6 +314,32 @@ bool Camera::is_position_behind(const Vector3 &p_pos) const {
return eyedir.dot(p_pos) < (eyedir.dot(t.origin) + near);
}
+Vector<Vector3> Camera::get_near_plane_points() const {
+ if (!is_inside_tree()) {
+ ERR_EXPLAIN("Camera is not inside scene.");
+ ERR_FAIL_COND_V(!is_inside_tree(), Vector<Vector3>());
+ }
+
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
+
+ CameraMatrix cm;
+
+ if (mode == PROJECTION_ORTHOGONAL)
+ cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+ else
+ cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH);
+
+ Vector3 endpoints[8];
+ cm.get_endpoints(Transform(), endpoints);
+
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ for (int i = 0; i < 4; i++) {
+ points.push_back(endpoints[i + 4]);
+ }
+ return points;
+}
+
Point2 Camera::unproject_position(const Vector3 &p_pos) const {
if (!is_inside_tree()) {
@@ -484,7 +511,7 @@ void Camera::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
@@ -638,3 +665,224 @@ Camera::~Camera() {
VisualServer::get_singleton()->free(camera);
}
+
+////////////////////////////////////////
+
+void ClippedCamera::set_margin(float p_margin) {
+ margin = p_margin;
+}
+float ClippedCamera::get_margin() const {
+ return margin;
+}
+void ClippedCamera::set_process_mode(ProcessMode p_mode) {
+
+ if (process_mode == p_mode) {
+ return;
+ }
+ set_process_internal(p_mode == CLIP_PROCESS_IDLE);
+ set_physics_process_internal(p_mode == CLIP_PROCESS_PHYSICS);
+}
+ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const {
+ return process_mode;
+}
+
+Transform ClippedCamera::get_camera_transform() const {
+
+ Transform t = Camera::get_camera_transform();
+ t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
+ return t;
+}
+
+void ClippedCamera::_notification(int p_what) {
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
+
+ Spatial *parent = Object::cast_to<Spatial>(get_parent());
+ if (!parent) {
+ return;
+ }
+
+ PhysicsDirectSpaceState *dspace = get_world()->get_direct_space_state();
+ ERR_FAIL_COND(!dspace); // most likely physics set to threads
+
+ Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
+ Vector3 cam_pos = get_global_transform().origin;
+ Vector3 parent_pos = parent->get_global_transform().origin;
+
+ Plane parent_plane(parent_pos, cam_fw);
+
+ if (parent_plane.is_point_over(cam_pos)) {
+ //cam is beyond parent plane
+ return;
+ }
+
+ Vector3 ray_from = parent_plane.project(cam_pos);
+
+ clip_offset = 0; //reset by defau;t
+
+ { //check if points changed
+ Vector<Vector3> local_points = get_near_plane_points();
+
+ bool all_equal = true;
+
+ for (int i = 0; i < 5; i++) {
+ if (points[i] != local_points[i]) {
+ all_equal = false;
+ break;
+ }
+ }
+
+ if (!all_equal) {
+ PhysicsServer::get_singleton()->shape_set_data(pyramid_shape, local_points);
+ points = local_points;
+ }
+ }
+
+ Transform xf = get_global_transform();
+ xf.origin = ray_from;
+ xf.orthonormalize();
+
+ float csafe, cunsafe;
+ if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
+ clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from).normalized() * csafe);
+ }
+
+ _update_camera();
+ }
+
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ update_gizmo();
+ }
+}
+
+void ClippedCamera::set_collision_mask(uint32_t p_mask) {
+
+ collision_mask = p_mask;
+}
+
+uint32_t ClippedCamera::get_collision_mask() const {
+
+ return collision_mask;
+}
+
+void ClippedCamera::set_collision_mask_bit(int p_bit, bool p_value) {
+
+ uint32_t mask = get_collision_mask();
+ if (p_value)
+ mask |= 1 << p_bit;
+ else
+ mask &= ~(1 << p_bit);
+ set_collision_mask(mask);
+}
+
+bool ClippedCamera::get_collision_mask_bit(int p_bit) const {
+
+ return get_collision_mask() & (1 << p_bit);
+}
+
+void ClippedCamera::add_exception_rid(const RID &p_rid) {
+
+ exclude.insert(p_rid);
+}
+
+void ClippedCamera::add_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
+ if (!co)
+ return;
+ add_exception_rid(co->get_rid());
+}
+
+void ClippedCamera::remove_exception_rid(const RID &p_rid) {
+
+ exclude.erase(p_rid);
+}
+
+void ClippedCamera::remove_exception(const Object *p_object) {
+
+ ERR_FAIL_NULL(p_object);
+ const CollisionObject *co = Object::cast_to<CollisionObject>(p_object);
+ if (!co)
+ return;
+ remove_exception_rid(co->get_rid());
+}
+
+void ClippedCamera::clear_exceptions() {
+
+ exclude.clear();
+}
+
+void ClippedCamera::set_clip_to_areas(bool p_clip) {
+
+ clip_to_areas = p_clip;
+}
+
+bool ClippedCamera::is_clip_to_areas_enabled() const {
+
+ return clip_to_areas;
+}
+
+void ClippedCamera::set_clip_to_bodies(bool p_clip) {
+
+ clip_to_bodies = p_clip;
+}
+
+bool ClippedCamera::is_clip_to_bodies_enabled() const {
+
+ return clip_to_bodies;
+}
+
+void ClippedCamera::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera::get_margin);
+
+ ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera::set_process_mode);
+ ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera::get_process_mode);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera::get_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera::get_collision_mask_bit);
+
+ ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera::add_exception_rid);
+ ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera::add_exception);
+
+ ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera::remove_exception_rid);
+ ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera::remove_exception);
+
+ ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas);
+ ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies);
+ ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled);
+
+ ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera::clear_exceptions);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Clip To", "clip_to");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
+
+ BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
+ BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
+}
+ClippedCamera::ClippedCamera() {
+ margin = 0;
+ clip_offset = 0;
+ process_mode = CLIP_PROCESS_PHYSICS;
+ set_physics_process_internal(true);
+ collision_mask = 1;
+ set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
+ points.resize(5);
+ pyramid_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON);
+ clip_to_areas = false;
+ clip_to_bodies = true;
+}
+ClippedCamera::~ClippedCamera() {
+ PhysicsServer::get_singleton()->free(pyramid_shape);
+}
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 97705d8ae0..a35c9d6e7f 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -139,6 +139,8 @@ public:
bool is_position_behind(const Vector3 &p_pos) const;
virtual Vector3 project_position(const Point2 &p_point) const;
+ Vector<Vector3> get_near_plane_points() const;
+
void set_cull_mask(uint32_t p_layers);
uint32_t get_cull_mask() const;
@@ -172,4 +174,62 @@ VARIANT_ENUM_CAST(Camera::Projection);
VARIANT_ENUM_CAST(Camera::KeepAspect);
VARIANT_ENUM_CAST(Camera::DopplerTracking);
+class ClippedCamera : public Camera {
+
+ GDCLASS(ClippedCamera, Camera);
+
+public:
+ enum ProcessMode {
+ CLIP_PROCESS_PHYSICS,
+ CLIP_PROCESS_IDLE,
+ };
+
+private:
+ ProcessMode process_mode;
+ RID pyramid_shape;
+ float margin;
+ float clip_offset;
+ uint32_t collision_mask;
+ bool clip_to_areas;
+ bool clip_to_bodies;
+
+ Set<RID> exclude;
+
+ Vector<Vector3> points;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+ virtual Transform get_camera_transform() const;
+
+public:
+ void set_clip_to_areas(bool p_clip);
+ bool is_clip_to_areas_enabled() const;
+
+ void set_clip_to_bodies(bool p_clip);
+ bool is_clip_to_bodies_enabled() const;
+
+ void set_margin(float p_margin);
+ float get_margin() const;
+
+ void set_process_mode(ProcessMode p_mode);
+ ProcessMode get_process_mode() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
+ void add_exception_rid(const RID &p_rid);
+ void add_exception(const Object *p_object);
+ void remove_exception_rid(const RID &p_rid);
+ void remove_exception(const Object *p_object);
+ void clear_exceptions();
+
+ ClippedCamera();
+ ~ClippedCamera();
+};
+
+VARIANT_ENUM_CAST(ClippedCamera::ProcessMode);
#endif
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 8b2000d2e9..af8bfcbe9b 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -921,8 +921,6 @@ void CPUParticles::_update_particle_data_buffer() {
t = un_transform * t;
}
- // print_line(" particle " + itos(i) + ": " + String(r[idx].active ? "[x]" : "[ ]") + "\n\txform " + r[idx].transform + "\n\t" + r[idx].velocity + "\n\tcolor: " + r[idx].color);
-
if (r[idx].active) {
ptr[0] = t.basis.elements[0][0];
ptr[1] = t.basis.elements[0][1];
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index f5b77d361c..8d84d2408c 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -120,9 +120,7 @@ void Navigation::_navmesh_link(int p_id) {
pending.edge = j;
p.edges.write[j].P = C->get().pending.push_back(pending);
continue;
- //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b));
}
- //ERR_CONTINUE(C->get().B!=NULL); //wut
C->get().B = &p;
C->get().B_edge = j;
@@ -312,7 +310,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
if (!begin_poly || !end_poly) {
- //print_line("No Path Path");
return Vector<Vector3>(); //no path
}
@@ -322,7 +319,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
path.resize(2);
path.write[0] = begin_point;
path.write[1] = end_point;
- //print_line("Direct Path");
return path;
}
@@ -347,7 +343,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector
while (!found_route) {
if (open_list.size() == 0) {
- //print_line("NOU OPEN LIST");
break;
}
//check open list
@@ -581,10 +576,6 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve
}
}
- if (closest_navmesh && closest_navmesh->owner) {
- //print_line("navmesh is: "+Object::cast_to<Node>(closest_navmesh->owner)->get_name());
- }
-
return closest_point;
}
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index e53ccb4cf4..2df6ef7c8a 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1078,10 +1078,10 @@ void RigidBody::_reload_physics_characteristics() {
//////////////////////////////////////////////////////
//////////////////////////
-Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia) {
+Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_test_only) {
Collision col;
- if (move_and_collide(p_motion, p_infinite_inertia, col)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -1095,7 +1095,7 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf
return Ref<KinematicCollision>();
}
-bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision) {
+bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_test_only) {
Transform gt = get_global_transform();
PhysicsServer::MotionResult result;
@@ -1108,6 +1108,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
r_collision.collision = result.collision_point;
r_collision.normal = result.collision_normal;
r_collision.collider = result.collider_id;
+ r_collision.collider_rid = result.collider;
r_collision.travel = result.motion;
r_collision.remainder = result.remainder;
r_collision.local_shape = result.collision_local_shape;
@@ -1119,8 +1120,10 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
}
}
- gt.origin += result.motion;
- set_global_transform(gt);
+ if (!p_test_only) {
+ gt.origin += result.motion;
+ set_global_transform(gt);
+ }
return colliding;
}
@@ -1128,7 +1131,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
-Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
+Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector3 lv = p_linear_velocity;
@@ -1146,69 +1149,127 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
colliders.clear();
floor_velocity = Vector3();
+ Vector3 lv_n = p_linear_velocity.normalized();
+
while (p_max_slides) {
Collision collision;
- bool collided = move_and_collide(motion, p_infinite_inertia, collision);
-
- if (collided) {
+ bool found_collision = false;
- motion = collision.remainder;
+ int test_type = 0;
- if (p_floor_direction == Vector3()) {
- //all is a wall
- on_wall = true;
+ do {
+ bool collided;
+ if (test_type == 0) { //collide
+ collided = move_and_collide(motion, p_infinite_inertia, collision);
+ if (!collided) {
+ motion = Vector3(); //clear because no collision happened and motion completed
+ }
} else {
- if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
+ collided = separate_raycast_shapes(p_infinite_inertia, collision);
+ if (collided) {
+ collision.remainder = motion; //keep
+ collision.travel = Vector3();
+ }
+ }
- on_floor = true;
- floor_velocity = collision.collider_vel;
+ if (collided) {
+ found_collision = true;
+ }
- Vector3 rel_v = lv - floor_velocity;
- Vector3 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v);
+ if (collided) {
- if (collision.travel.length() < 0.05 && hv.length() < p_slope_stop_min_velocity) {
- Transform gt = get_global_transform();
- gt.origin -= collision.travel;
- set_global_transform(gt);
- return floor_velocity - p_floor_direction * p_floor_direction.dot(floor_velocity);
- }
- } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
- on_ceiling = true;
- } else {
+ colliders.push_back(collision);
+ motion = collision.remainder;
+
+ bool is_on_slope = false;
+ if (p_floor_direction == Vector3()) {
+ //all is a wall
on_wall = true;
+ } else {
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor
+
+ on_floor = true;
+ on_floor_body = collision.collider_rid;
+ floor_velocity = collision.collider_vel;
+
+ if (p_stop_on_slope) {
+ if (Vector3() == lv_n + p_floor_direction) {
+ Transform gt = get_global_transform();
+ gt.origin -= collision.travel;
+ set_global_transform(gt);
+ return Vector3();
+ }
+ }
+
+ is_on_slope = true;
+
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
+ }
}
- }
- Vector3 n = collision.normal;
- motion = motion.slide(n);
- lv = lv.slide(n);
+ if (p_stop_on_slope && is_on_slope) {
+ motion = motion.slide(p_floor_direction);
+ lv = lv.slide(p_floor_direction);
+ } else {
+ Vector3 n = collision.normal;
+ motion = motion.slide(n);
+ lv = lv.slide(n);
+ }
- for (int i = 0; i < 3; i++) {
- if (locked_axis & (1 << i)) {
- lv[i] = 0;
+ for (int i = 0; i < 3; i++) {
+ if (locked_axis & (1 << i)) {
+ lv[i] = 0;
+ }
}
}
- colliders.push_back(collision);
+ ++test_type;
+ } while (!p_stop_on_slope && test_type < 2);
- } else {
+ if (!found_collision || motion == Vector3())
break;
- }
- p_max_slides--;
- if (motion == Vector3())
- break;
+ --p_max_slides;
}
return lv;
}
+Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) {
+
+ bool was_on_floor = on_floor;
+
+ Vector3 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia);
+ if (!was_on_floor || p_snap == Vector3()) {
+ return ret;
+ }
+
+ Collision col;
+ Transform gt = get_global_transform();
+
+ if (move_and_collide(p_snap, p_infinite_inertia, col, true)) {
+ gt.origin += col.travel;
+ if (p_floor_direction != Vector3() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) {
+ on_floor = true;
+ on_floor_body = col.collider_rid;
+ floor_velocity = col.collider_vel;
+ }
+ set_global_transform(gt);
+ }
+
+ return ret;
+}
+
bool KinematicBody::is_on_floor() const {
return on_floor;
}
+
bool KinematicBody::is_on_wall() const {
return on_wall;
@@ -1230,6 +1291,43 @@ bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion,
return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
}
+bool KinematicBody::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {
+
+ PhysicsServer::SeparationResult sep_res[8]; //max 8 rays
+
+ Transform gt = get_global_transform();
+
+ Vector3 recover;
+ int hits = PhysicsServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin);
+ int deepest = -1;
+ float deepest_depth;
+ for (int i = 0; i < hits; i++) {
+ if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
+ deepest = i;
+ deepest_depth = sep_res[i].collision_depth;
+ }
+ }
+
+ gt.origin += recover;
+ set_global_transform(gt);
+
+ if (deepest != -1) {
+ r_collision.collider = sep_res[deepest].collider_id;
+ r_collision.collider_metadata = sep_res[deepest].collider_metadata;
+ r_collision.collider_shape = sep_res[deepest].collider_shape;
+ r_collision.collider_vel = sep_res[deepest].collider_velocity;
+ r_collision.collision = sep_res[deepest].collision_point;
+ r_collision.normal = sep_res[deepest].collision_normal;
+ r_collision.local_shape = sep_res[deepest].collision_local_shape;
+ r_collision.travel = recover;
+ r_collision.remainder = Vector3();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) {
PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock);
}
@@ -1276,8 +1374,9 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
void KinematicBody::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody::_move, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move);
@@ -1295,13 +1394,9 @@ void KinematicBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision);
- ADD_GROUP("Axis Lock", "axis_lock_");
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 80bf422c98..c4db41f577 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -285,6 +285,7 @@ public:
Vector3 normal;
Vector3 collider_vel;
ObjectID collider;
+ RID collider_rid;
int collider_shape;
Variant collider_metadata;
Vector3 remainder;
@@ -298,6 +299,7 @@ private:
float margin;
Vector3 floor_velocity;
+ RID on_floor_body;
bool on_floor;
bool on_ceiling;
bool on_wall;
@@ -307,23 +309,26 @@ private:
_FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const;
- Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true);
+ Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_test_only = false);
Ref<KinematicCollision> _get_slide_collision(int p_bounce);
protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz);
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz, bool p_test_only = false);
bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
+ bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);
+
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
void set_safe_margin(float p_margin);
float get_safe_margin() const;
- Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
+ Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true);
+ Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index 7f83e2c3ea..b846a5b6c0 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -208,7 +208,7 @@ void RayCast::_update_raycast_state() {
PhysicsDirectSpaceState::RayResult rr;
- if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask)) {
+ if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) {
collided = true;
against = rr.collider_id;
@@ -259,6 +259,26 @@ void RayCast::clear_exceptions() {
exclude.clear();
}
+void RayCast::set_collide_with_areas(bool p_clip) {
+
+ collide_with_areas = p_clip;
+}
+
+bool RayCast::is_collide_with_areas_enabled() const {
+
+ return collide_with_areas;
+}
+
+void RayCast::set_collide_with_bodies(bool p_clip) {
+
+ collide_with_bodies = p_clip;
+}
+
+bool RayCast::is_collide_with_bodies_enabled() const {
+
+ return collide_with_bodies;
+}
+
void RayCast::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast::set_enabled);
@@ -292,10 +312,20 @@ void RayCast::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast::get_exclude_parent_body);
+ ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast::set_collide_with_areas);
+ ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast::is_collide_with_areas_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast::set_collide_with_bodies);
+ ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast::is_collide_with_bodies_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Collide With", "collide_with");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
}
void RayCast::_create_debug_shape() {
@@ -370,4 +400,6 @@ RayCast::RayCast() {
cast_to = Vector3(0, -1, 0);
debug_shape = NULL;
exclude_parent_body = true;
+ collide_with_areas = false;
+ collide_with_bodies = true;
}
diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h
index 20cea80700..e95382e1fe 100644
--- a/scene/3d/ray_cast.h
+++ b/scene/3d/ray_cast.h
@@ -45,7 +45,6 @@ class RayCast : public Spatial {
Vector3 collision_normal;
Vector3 cast_to;
-
Set<RID> exclude;
uint32_t collision_mask;
@@ -58,12 +57,21 @@ class RayCast : public Spatial {
void _update_debug_shape();
void _clear_debug_shape();
+ bool collide_with_areas;
+ bool collide_with_bodies;
+
protected:
void _notification(int p_what);
void _update_raycast_state();
static void _bind_methods();
public:
+ void set_collide_with_areas(bool p_clip);
+ bool is_collide_with_areas_enabled() const;
+
+ void set_collide_with_bodies(bool p_clip);
+ bool is_collide_with_bodies_enabled() const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
index 2156e24cd0..c12e49fb47 100644
--- a/scene/3d/remote_transform.cpp
+++ b/scene/3d/remote_transform.cpp
@@ -124,8 +124,10 @@ void RemoteTransform::_notification(int p_what) {
void RemoteTransform::set_remote_node(const NodePath &p_remote_node) {
remote_node = p_remote_node;
- if (is_inside_tree())
+ if (is_inside_tree()) {
_update_cache();
+ _update_remote();
+ }
update_configuration_warning();
}
diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp
new file mode 100644
index 0000000000..492c6b806e
--- /dev/null
+++ b/scene/3d/spring_arm.cpp
@@ -0,0 +1,172 @@
+/*************************************************************************/
+/* spring_arm.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 "spring_arm.h"
+#include "engine.h"
+#include "scene/3d/collision_object.h"
+#include "scene/resources/sphere_shape.h"
+#include "servers/physics_server.h"
+
+SpringArm::SpringArm() :
+ spring_length(1),
+ mask(1),
+ current_spring_length(0),
+ margin(0.01) {}
+
+void SpringArm::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ set_process_internal(true);
+ }
+ break;
+ case NOTIFICATION_EXIT_TREE:
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ set_process_internal(false);
+ }
+ break;
+ case NOTIFICATION_INTERNAL_PROCESS:
+ process_spring();
+ break;
+ }
+}
+
+void SpringArm::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm::get_hit_length);
+
+ ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm::set_length);
+ ClassDB::bind_method(D_METHOD("get_length"), &SpringArm::get_length);
+
+ ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm::set_shape);
+ ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm::get_shape);
+
+ ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm::add_excluded_object);
+ ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm::remove_excluded_object);
+ ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm::clear_excluded_objects);
+
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm::set_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm::get_mask);
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm::get_margin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "spring_length"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin"), "set_margin", "get_margin");
+}
+
+float SpringArm::get_length() const {
+ return spring_length;
+}
+
+void SpringArm::set_length(float p_length) {
+ if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint()))
+ update_gizmo();
+
+ spring_length = p_length;
+}
+
+void SpringArm::set_shape(Ref<Shape> p_shape) {
+ shape = p_shape;
+}
+
+Ref<Shape> SpringArm::get_shape() const {
+ return shape;
+}
+
+void SpringArm::set_mask(uint32_t p_mask) {
+ mask = p_mask;
+}
+
+uint32_t SpringArm::get_mask() {
+ return mask;
+}
+
+float SpringArm::get_margin() {
+ return margin;
+}
+
+void SpringArm::set_margin(float p_margin) {
+ margin = p_margin;
+}
+
+void SpringArm::add_excluded_object(RID p_rid) {
+ excluded_objects.insert(p_rid);
+}
+
+bool SpringArm::remove_excluded_object(RID p_rid) {
+ return excluded_objects.erase(p_rid);
+}
+
+void SpringArm::clear_excluded_objects() {
+ excluded_objects.clear();
+}
+
+float SpringArm::get_hit_length() {
+ return current_spring_length;
+}
+
+void SpringArm::process_spring() {
+ // From
+ real_t motion_delta(1);
+ real_t motion_delta_unsafe(1);
+
+ Vector3 motion;
+ const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
+
+ if (shape.is_null()) {
+ motion = Vector3(cast_direction * (spring_length));
+ PhysicsDirectSpaceState::RayResult r;
+ bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
+ if (intersected) {
+ float dist = get_global_transform().origin.distance_to(r.position);
+ dist -= margin;
+ motion_delta = dist / (spring_length);
+ }
+ } else {
+ motion = Vector3(cast_direction * spring_length);
+ get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
+ }
+
+ current_spring_length = spring_length * motion_delta;
+ Transform childs_transform;
+ childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta);
+
+ for (int i = get_child_count() - 1; 0 <= i; --i) {
+
+ Spatial *child = Object::cast_to<Spatial>(get_child(i));
+ if (child) {
+ childs_transform.basis = child->get_global_transform().basis;
+ child->set_global_transform(childs_transform);
+ }
+ }
+}
diff --git a/scene/3d/spring_arm.h b/scene/3d/spring_arm.h
new file mode 100644
index 0000000000..24d912d371
--- /dev/null
+++ b/scene/3d/spring_arm.h
@@ -0,0 +1,71 @@
+/*************************************************************************/
+/* spring_arm.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. */
+/*************************************************************************/
+
+#ifndef SPRING_ARM_H
+#define SPRING_ARM_H
+
+#include "scene/3d/spatial.h"
+
+class SpringArm : public Spatial {
+ GDCLASS(SpringArm, Spatial);
+
+ Ref<Shape> shape;
+ Set<RID> excluded_objects;
+ float spring_length;
+ bool keep_child_basis;
+ float current_spring_length;
+ uint32_t mask;
+ float margin;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_length(float p_length);
+ float get_length() const;
+ void set_shape(Ref<Shape> p_shape);
+ Ref<Shape> get_shape() const;
+ void set_mask(uint32_t p_mask);
+ uint32_t get_mask();
+ void add_excluded_object(RID p_rid);
+ bool remove_excluded_object(RID p_rid);
+ void clear_excluded_objects();
+ float get_hit_length();
+ void set_margin(float p_margin);
+ float get_margin();
+
+ SpringArm();
+
+private:
+ void process_spring();
+};
+
+#endif
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index 26958930e4..f9d096633c 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -366,22 +366,14 @@ void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) {
const Vector3 &right = wheel.m_raycastInfo.m_wheelAxleWS;
Vector3 fwd = up.cross(right);
fwd = fwd.normalized();
- //up = right.cross(fwd);
- //up.normalize();
//rotate around steering over de wheelAxleWS
real_t steering = wheel.steers ? m_steeringValue : 0.0;
- //print_line(itos(p_idx)+": "+rtos(steering));
Basis steeringMat(up, steering);
Basis rotatingMat(right, wheel.m_rotation);
- /*
- if (p_idx==1)
- print_line("steeringMat " +steeringMat);
- */
-
Basis basis2(
right[0], up[0], fwd[0],
right[1], up[1], fwd[1],
@@ -420,8 +412,6 @@ real_t VehicleBody::_ray_cast(int p_idx, PhysicsDirectBodyState *s) {
wheel.m_raycastInfo.m_groundObject = 0;
if (col) {
- //print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target);
- //print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col));
param = source.distance_to(rr.position) / source.distance_to(target);
depth = raylen * param;
wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index f3abdc6bbe..e846e1763d 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -491,8 +491,6 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color
p_image = p_image->duplicate();
if (p_image->is_compressed()) {
- print_line("DECOMPRESSING!!!!");
-
p_image->decompress();
}
p_image->convert(Image::FORMAT_RGBA8);
@@ -859,7 +857,6 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
int idx = first_leaf;
while (idx >= 0) {
- //print_line("plot idx " + itos(idx));
Light *light = &light_data[idx];
Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
@@ -949,7 +946,6 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
int idx = first_leaf;
while (idx >= 0) {
- //print_line("plot idx " + itos(idx));
Light *light = &light_data[idx];
Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
@@ -1079,7 +1075,6 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
int idx = first_leaf;
while (idx >= 0) {
- //print_line("plot idx " + itos(idx));
Light *light = &light_data[idx];
Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5);
@@ -1498,12 +1493,8 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
for (int i = 0; i < 6; i++) {
//anisotropic read light
float amount = p_direction.dot(aniso_normal[i]);
- //if (c == 0) {
- // print_line("\t" + itos(n) + " aniso " + itos(i) + " " + rtos(light[cell].accum[i][0]) + " VEC: " + aniso_normal[i]);
- //}
if (amount < 0)
amount = 0;
- //amount = 1;
color[c][n].x += light[cell].accum[i][0] * amount;
color[c][n].y += light[cell].accum[i][1] * amount;
color[c][n].z += light[cell].accum[i][2] * amount;
@@ -1513,8 +1504,6 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
color[c][n].y += cells[cell].emission[1];
color[c][n].z += cells[cell].emission[2];
}
-
- //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]);
}
}
@@ -1559,8 +1548,6 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter);
r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter);
-
- // print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha));
}
Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture) {
@@ -1577,8 +1564,6 @@ Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &
while (dist < max_distance && alpha < 0.95) {
float diameter = MAX(1.0, 2.0 * p_aperture * dist);
- //print_line("VCT: pos " + (p_pos + dist * p_normal) + " dist " + rtos(dist) + " mipmap " + rtos(log2(diameter)) + " alpha " + rtos(alpha));
- //Plane scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
_sample_baked_octree_filtered_and_anisotropic(p_pos + dist * p_normal, p_normal, log2(diameter), scolor, salpha);
float a = (1.0 - alpha);
color += scolor * a;
@@ -1601,7 +1586,6 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3 bitangent = tangent.cross(p_normal).normalized();
Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed();
- // print_line("normal xform: " + normal_xform);
const Vector3 *cone_dirs;
const float *cone_weights;
int cone_dir_count;
@@ -1667,10 +1651,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3 accum;
for (int i = 0; i < cone_dir_count; i++) {
- // if (i > 0)
- // continue;
Vector3 dir = normal_xform.xform(cone_dirs[i]).normalized(); //normal may not completely correct when transformed to cell
- //print_line("direction: " + dir);
accum += _voxel_cone_trace(p_pos, dir, cone_aperture) * cone_weights[i];
}
@@ -1802,7 +1783,6 @@ void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
LightMap *pixel = &p_line[p_x];
if (pixel->pos == Vector3())
return;
- //print_line("pos: " + pixel->pos + " normal " + pixel->normal);
switch (bake_mode) {
case BAKE_MODE_CONE_TRACE: {
pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy;
@@ -1810,8 +1790,6 @@ void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
case BAKE_MODE_RAY_TRACE: {
pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy;
} break;
- // pixel->light = Vector3(1, 1, 1);
- //}
}
}
@@ -1895,7 +1873,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
if (bake_mode == BAKE_MODE_RAY_TRACE) {
//blur
- print_line("bluring, use pos for separatable copy");
//gauss kernel, 7 step sigma 2
static const float gauss_kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 };
//horizontal pass
@@ -1960,8 +1937,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
#pragma omp parallel
#endif
for (int i = 0; i < height; i++) {
-
- //print_line("bake line " + itos(i) + " / " + itos(height));
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, 1)
#endif
@@ -2304,7 +2279,6 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
mm->set_transform_format(MultiMesh::TRANSFORM_3D);
mm->set_color_format(MultiMesh::COLOR_8BIT);
- print_line("leaf voxels: " + itos(leaf_voxel_count));
mm->set_instance_count(leaf_voxel_count);
Ref<ArrayMesh> mesh;
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index 1bc9fa4b12..289cf7a3a7 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -1,12 +1,14 @@
#include "animation_blend_space_1d.h"
-void AnimationNodeBlendSpace1D::set_tree(AnimationTree *p_player) {
-
- AnimationRootNode::set_tree(p_player);
+void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, blend_position));
+}
+Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0;
+}
- for (int i = 0; i < blend_points_used; i++) {
- blend_points[i].node->set_tree(p_player);
- }
+Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
+ return get_blend_point_node(p_name.operator String().to_int());
}
void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const {
@@ -20,6 +22,10 @@ void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const
AnimationRootNode::_validate_property(property);
}
+void AnimationNodeBlendSpace1D::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace1D::add_blend_point, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace1D::set_blend_point_position);
@@ -38,30 +44,37 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace1D::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace1D::get_snap);
- ClassDB::bind_method(D_METHOD("set_blend_pos", "pos"), &AnimationNodeBlendSpace1D::set_blend_pos);
- ClassDB::bind_method(D_METHOD("get_blend_pos"), &AnimationNodeBlendSpace1D::get_blend_pos);
-
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace1D::_tree_changed);
+
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
}
ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "blend_pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_pos", "get_blend_pos");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_value_label", "get_value_label");
}
+void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ for (int i = 0; i < blend_points_used; i++) {
+ ChildNode cn;
+ cn.name = itos(i);
+ cn.node = blend_points[i].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) {
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
+
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
if (p_at_index == -1 || p_at_index == blend_points_used) {
@@ -75,10 +88,10 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_
blend_points[p_at_index].node = p_node;
blend_points[p_at_index].position = p_position;
- blend_points[p_at_index].node->set_parent(this);
- blend_points[p_at_index].node->set_tree(get_tree());
+ blend_points[p_at_index].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
blend_points_used++;
+ emit_signal("tree_changed");
}
void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) {
@@ -92,13 +105,13 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<Anim
ERR_FAIL_COND(p_node.is_null());
if (blend_points[p_point].node.is_valid()) {
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
}
blend_points[p_point].node = p_node;
- blend_points[p_point].node->set_parent(this);
- blend_points[p_point].node->set_tree(get_tree());
+ blend_points[p_point].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+
+ emit_signal("tree_changed");
}
float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const {
@@ -114,14 +127,14 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
for (int i = p_point; i < blend_points_used - 1; i++) {
blend_points[i] = blend_points[i + 1];
}
blend_points_used--;
+ emit_signal("tree_changed");
}
int AnimationNodeBlendSpace1D::get_blend_point_count() const {
@@ -161,14 +174,6 @@ float AnimationNodeBlendSpace1D::get_snap() const {
return snap;
}
-void AnimationNodeBlendSpace1D::set_blend_pos(float p_pos) {
- blend_pos = p_pos;
-}
-
-float AnimationNodeBlendSpace1D::get_blend_pos() const {
- return blend_pos;
-}
-
void AnimationNodeBlendSpace1D::set_value_label(const String &p_label) {
value_label = p_label;
}
@@ -193,9 +198,11 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
if (blend_points_used == 1) {
// only one point available, just play that animation
- return blend_node(blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
+ return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
}
+ float blend_pos = get_parameter(blend_position);
+
float weights[MAX_BLEND_POINTS] = {};
int point_lower = -1;
@@ -262,7 +269,7 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) {
float max_time_remaining = 0.0;
for (int i = 0; i < blend_points_used; i++) {
- float remaining = blend_node(blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
+ float remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false);
max_time_remaining = MAX(max_time_remaining, remaining);
}
@@ -276,18 +283,18 @@ String AnimationNodeBlendSpace1D::get_caption() const {
AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() {
+ for (int i = 0; i < MAX_BLEND_POINTS; i++) {
+ blend_points[i].name = itos(i);
+ }
blend_points_used = 0;
max_space = 1;
min_space = -1;
snap = 0.1;
value_label = "value";
+
+ blend_position = "blend_position";
}
AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() {
-
- for (int i = 0; i < blend_points_used; i++) {
- blend_points[i].node->set_parent(this);
- blend_points[i].node->set_tree(get_tree());
- }
}
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index d1ed4c6a1f..f4e20f0d70 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -11,6 +11,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
};
struct BlendPoint {
+ StringName name;
Ref<AnimationRootNode> node;
float position;
};
@@ -18,8 +19,6 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
BlendPoint blend_points[MAX_BLEND_POINTS];
int blend_points_used;
- float blend_pos;
-
float max_space;
float min_space;
@@ -29,12 +28,19 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node);
+ void _tree_changed();
+
+ StringName blend_position;
+
protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
- virtual void set_tree(AnimationTree *p_player);
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
void set_blend_point_position(int p_point, float p_position);
@@ -54,15 +60,14 @@ public:
void set_snap(float p_snap);
float get_snap() const;
- void set_blend_pos(float p_pos);
- float get_blend_pos() const;
-
void set_value_label(const String &p_label);
String get_value_label() const;
float process(float p_time, bool p_seek);
String get_caption() const;
+ Ref<AnimationNode> get_child_by_name(const StringName &p_name);
+
AnimationNodeBlendSpace1D();
~AnimationNodeBlendSpace1D();
};
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 3c93a0c8ec..3dc7f2a86f 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -1,18 +1,25 @@
#include "animation_blend_space_2d.h"
#include "math/delaunay.h"
-void AnimationNodeBlendSpace2D::set_tree(AnimationTree *p_player) {
- AnimationRootNode::set_tree(p_player);
+void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position));
+}
+Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const {
+ return Vector2();
+}
+void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
for (int i = 0; i < blend_points_used; i++) {
- blend_points[i].node->set_tree(p_player);
+ ChildNode cn;
+ cn.name = itos(i);
+ cn.node = blend_points[i].node;
+ r_child_nodes->push_back(cn);
}
}
void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) {
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
if (p_at_index == -1 || p_at_index == blend_points_used) {
@@ -32,13 +39,13 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_
blend_points[p_at_index].node = p_node;
blend_points[p_at_index].position = p_position;
- blend_points[p_at_index].node->set_parent(this);
- blend_points[p_at_index].node->set_tree(get_tree());
+ blend_points[p_at_index].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
blend_points_used++;
if (auto_triangles) {
trianges_dirty = true;
}
+ emit_signal("tree_changed");
}
void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) {
@@ -53,12 +60,12 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<Anim
ERR_FAIL_COND(p_node.is_null());
if (blend_points[p_point].node.is_valid()) {
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
}
blend_points[p_point].node = p_node;
- blend_points[p_point].node->set_parent(this);
- blend_points[p_point].node->set_tree(get_tree());
+ blend_points[p_point].node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+
+ emit_signal("tree_changed");
}
Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const {
ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2());
@@ -71,8 +78,7 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_poi
void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
ERR_FAIL_INDEX(p_point, blend_points_used);
- blend_points[p_point].node->set_parent(NULL);
- blend_points[p_point].node->set_tree(NULL);
+ blend_points[p_point].node->disconnect("tree_changed", this, "_tree_changed");
for (int i = 0; i < triangles.size(); i++) {
bool erase = false;
@@ -95,6 +101,7 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
blend_points[i] = blend_points[i + 1];
}
blend_points_used--;
+ emit_signal("tree_changed");
}
int AnimationNodeBlendSpace2D::get_blend_point_count() const {
@@ -217,13 +224,6 @@ Vector2 AnimationNodeBlendSpace2D::get_snap() const {
return snap;
}
-void AnimationNodeBlendSpace2D::set_blend_position(const Vector2 &p_pos) {
- blend_pos = p_pos;
-}
-Vector2 AnimationNodeBlendSpace2D::get_blend_position() const {
- return blend_pos;
-}
-
void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) {
x_label = p_label;
}
@@ -381,6 +381,8 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
_update_triangles();
+ Vector2 blend_pos = get_parameter(blend_position);
+
if (triangles.size() == 0)
return 0;
@@ -443,7 +445,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
for (int j = 0; j < 3; j++) {
if (i == triangle_points[j]) {
//blend with the given weight
- float t = blend_node(blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
+ float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
if (first || t < mind) {
mind = t;
first = false;
@@ -455,7 +457,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
if (!found) {
//ignore
- blend_node(blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
}
}
return mind;
@@ -487,6 +489,14 @@ bool AnimationNodeBlendSpace2D::get_auto_triangles() const {
return auto_triangles;
}
+Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) {
+ return get_blend_point_node(p_name.operator String().to_int());
+}
+
+void AnimationNodeBlendSpace2D::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
@@ -511,9 +521,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap);
ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap);
- ClassDB::bind_method(D_METHOD("set_blend_position", "pos"), &AnimationNodeBlendSpace2D::set_blend_position);
- ClassDB::bind_method(D_METHOD("get_blend_position"), &AnimationNodeBlendSpace2D::get_blend_position);
-
ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace2D::set_x_label);
ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace2D::get_x_label);
@@ -528,10 +535,12 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles);
ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles");
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
}
@@ -540,13 +549,15 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "blend_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_position", "get_blend_position");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label");
}
AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
+ for (int i = 0; i < MAX_BLEND_POINTS; i++) {
+ blend_points[i].name = itos(i);
+ }
auto_triangles = true;
blend_points_used = 0;
max_space = Vector2(1, 1);
@@ -555,12 +566,8 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
x_label = "x";
y_label = "y";
trianges_dirty = false;
+ blend_position = "blend_position";
}
AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {
-
- for (int i = 0; i < blend_points_used; i++) {
- blend_points[i].node->set_parent(this);
- blend_points[i].node->set_tree(get_tree());
- }
}
diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h
index 74d20b6013..3e1c66c924 100644
--- a/scene/animation/animation_blend_space_2d.h
+++ b/scene/animation/animation_blend_space_2d.h
@@ -11,6 +11,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
};
struct BlendPoint {
+ StringName name;
Ref<AnimationRootNode> node;
Vector2 position;
};
@@ -24,7 +25,7 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
Vector<BlendTriangle> triangles;
- Vector2 blend_pos;
+ StringName blend_position;
Vector2 max_space;
Vector2 min_space;
Vector2 snap;
@@ -42,12 +43,17 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
void _update_triangles();
+ void _tree_changed();
+
protected:
virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
public:
- virtual void set_tree(AnimationTree *p_player);
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1);
void set_blend_point_position(int p_point, const Vector2 &p_position);
@@ -72,9 +78,6 @@ public:
void set_snap(const Vector2 &p_snap);
Vector2 get_snap() const;
- void set_blend_position(const Vector2 &p_pos);
- Vector2 get_blend_position() const;
-
void set_x_label(const String &p_label);
String get_x_label() const;
@@ -89,6 +92,8 @@ public:
void set_auto_triangles(bool p_enable);
bool get_auto_triangles() const;
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
+
AnimationNodeBlendSpace2D();
~AnimationNodeBlendSpace2D();
};
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 65904410d3..10bab3ce38 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -3,6 +3,7 @@
void AnimationNodeAnimation::set_animation(const StringName &p_name) {
animation = p_name;
+ _change_notify("animation");
}
StringName AnimationNodeAnimation::get_animation() const {
@@ -13,43 +14,36 @@ float AnimationNodeAnimation::get_playback_time() const {
return time;
}
+Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL;
+
void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
- if (property.name == "animation") {
- AnimationTree *gp = get_tree();
- if (gp && gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
- String anims;
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- if (E != names.front()) {
- anims += ",";
- }
- anims += String(E->get());
- }
- if (anims != String()) {
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = anims;
- }
+ if (property.name == "animation" && get_editable_animation_list) {
+ Vector<String> names = get_editable_animation_list();
+ String anims;
+ for (int i = 0; i < names.size(); i++) {
+
+ if (i > 0) {
+ anims += ",";
}
+ anims += String(names[i]);
+ }
+ if (anims != String()) {
+ property.hint = PROPERTY_HINT_ENUM;
+ property.hint_string = anims;
}
}
-
- AnimationRootNode::_validate_property(property);
}
float AnimationNodeAnimation::process(float p_time, bool p_seek) {
- AnimationPlayer *ap = get_player();
+ AnimationPlayer *ap = state->player;
ERR_FAIL_COND_V(!ap, 0);
- Ref<Animation> anim = ap->get_animation(animation);
- if (!anim.is_valid()) {
+ if (!ap->has_animation(animation)) {
- Ref<AnimationNodeBlendTree> tree = get_parent();
- if (tree.is_valid()) {
+ AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
+ if (tree) {
String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation));
@@ -60,6 +54,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) {
return 0;
}
+ Ref<Animation> anim = ap->get_animation(animation);
+
if (p_seek) {
time = p_time;
step = 0;
@@ -108,6 +104,20 @@ AnimationNodeAnimation::AnimationNodeAnimation() {
////////////////////////////////////////////////////////
+void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::BOOL, active));
+ r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, remaining, PROPERTY_HINT_NONE, "", 0));
+}
+Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
+ if (p_parameter == active || p_parameter == prev_active) {
+ return false;
+ } else {
+ return 0.0;
+ }
+}
+
void AnimationNodeOneShot::set_fadein_time(float p_time) {
fade_in = p_time;
@@ -162,18 +172,6 @@ AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const {
return mix;
}
-void AnimationNodeOneShot::start() {
- active = true;
- do_start = true;
-}
-void AnimationNodeOneShot::stop() {
- active = false;
-}
-bool AnimationNodeOneShot::is_active() const {
-
- return active;
-}
-
String AnimationNodeOneShot::get_caption() const {
return "OneShot";
}
@@ -184,8 +182,16 @@ bool AnimationNodeOneShot::has_filter() const {
float AnimationNodeOneShot::process(float p_time, bool p_seek) {
+ bool active = get_parameter(this->active);
+ bool prev_active = get_parameter(this->prev_active);
+ float time = get_parameter(this->time);
+ float remaining = get_parameter(this->remaining);
+
if (!active) {
//make it as if this node doesn't exist, pass input 0 by.
+ if (prev_active) {
+ set_parameter(this->prev_active, false);
+ }
return blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
}
@@ -193,9 +199,12 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (p_seek)
time = p_time;
+ bool do_start = !prev_active;
+
if (do_start) {
time = 0;
os_seek = true;
+ set_parameter(this->prev_active, true);
}
float blend;
@@ -233,10 +242,15 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) {
if (!p_seek) {
time += p_time;
remaining = os_rem;
- if (remaining <= 0)
- active = false;
+ if (remaining <= 0) {
+ set_parameter(this->active, false);
+ set_parameter(this->prev_active, false);
+ }
}
+ set_parameter(this->time, time);
+ set_parameter(this->remaining, remaining);
+
return MAX(main_rem, remaining);
}
void AnimationNodeOneShot::set_use_sync(bool p_sync) {
@@ -269,10 +283,6 @@ void AnimationNodeOneShot::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_mode", "mode"), &AnimationNodeOneShot::set_mix_mode);
ClassDB::bind_method(D_METHOD("get_mix_mode"), &AnimationNodeOneShot::get_mix_mode);
- ClassDB::bind_method(D_METHOD("start"), &AnimationNodeOneShot::start);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeOneShot::stop);
- ClassDB::bind_method(D_METHOD("is_active"), &AnimationNodeOneShot::is_active);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeOneShot::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeOneShot::is_using_sync);
@@ -297,26 +307,27 @@ AnimationNodeOneShot::AnimationNodeOneShot() {
add_input("in");
add_input("shot");
- time = 0;
fade_in = 0.1;
fade_out = 0.1;
autorestart = false;
autorestart_delay = 1;
- autorestart_remaining = 0;
+
mix = MIX_MODE_BLEND;
- active = false;
- do_start = false;
sync = false;
+
+ active = "active";
+ prev_active = "prev_active";
+ time = "time";
+ remaining = "remaining";
}
////////////////////////////////////////////////
-void AnimationNodeAdd2::set_amount(float p_amount) {
- amount = p_amount;
+void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
}
-
-float AnimationNodeAdd2::get_amount() const {
- return amount;
+Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0;
}
String AnimationNodeAdd2::get_caption() const {
@@ -339,6 +350,7 @@ bool AnimationNodeAdd2::has_filter() const {
float AnimationNodeAdd2::process(float p_time, bool p_seek) {
+ float amount = get_parameter(add_amount);
float rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
@@ -347,32 +359,27 @@ float AnimationNodeAdd2::process(float p_time, bool p_seek) {
void AnimationNodeAdd2::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd2::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd2::get_amount);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd2::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd2::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeAdd2::AnimationNodeAdd2() {
+ add_amount = "add_amount";
add_input("in");
add_input("add");
- amount = 0;
sync = false;
}
////////////////////////////////////////////////
-void AnimationNodeAdd3::set_amount(float p_amount) {
- amount = p_amount;
+void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
}
-
-float AnimationNodeAdd3::get_amount() const {
- return amount;
+Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0;
}
String AnimationNodeAdd3::get_caption() const {
@@ -395,6 +402,7 @@ bool AnimationNodeAdd3::has_filter() const {
float AnimationNodeAdd3::process(float p_time, bool p_seek) {
+ float amount = get_parameter(add_amount);
blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_PASS, !sync);
float rem0 = blend_input(1, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_PASS, !sync);
@@ -404,39 +412,37 @@ float AnimationNodeAdd3::process(float p_time, bool p_seek) {
void AnimationNodeAdd3::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeAdd3::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeAdd3::get_amount);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeAdd3::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeAdd3::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeAdd3::AnimationNodeAdd3() {
+ add_amount = "add_amount";
add_input("-add");
add_input("in");
add_input("+add");
- amount = 0;
sync = false;
}
/////////////////////////////////////////////
-void AnimationNodeBlend2::set_amount(float p_amount) {
- amount = p_amount;
+void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01"));
}
-
-float AnimationNodeBlend2::get_amount() const {
- return amount;
+Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0; //for blend amount
}
+
String AnimationNodeBlend2::get_caption() const {
return "Blend2";
}
float AnimationNodeBlend2::process(float p_time, bool p_seek) {
+ float amount = get_parameter(blend_amount);
+
float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync);
float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync);
@@ -459,31 +465,25 @@ bool AnimationNodeBlend2::has_filter() const {
}
void AnimationNodeBlend2::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend2::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend2::get_amount);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend2::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend2::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend2::AnimationNodeBlend2() {
+ blend_amount = "blend_amount";
add_input("in");
add_input("blend");
sync = false;
-
- amount = 0;
}
//////////////////////////////////////
-void AnimationNodeBlend3::set_amount(float p_amount) {
- amount = p_amount;
+void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01"));
}
-
-float AnimationNodeBlend3::get_amount() const {
- return amount;
+Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
+ return 0; //for blend amount
}
String AnimationNodeBlend3::get_caption() const {
@@ -502,6 +502,7 @@ bool AnimationNodeBlend3::is_using_sync() const {
float AnimationNodeBlend3::process(float p_time, bool p_seek) {
+ float amount = get_parameter(blend_amount);
float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync);
float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync);
float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync);
@@ -511,31 +512,26 @@ float AnimationNodeBlend3::process(float p_time, bool p_seek) {
void AnimationNodeBlend3::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_amount", "amount"), &AnimationNodeBlend3::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &AnimationNodeBlend3::get_amount);
-
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlend3::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlend3::is_using_sync);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "amount", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync"), "set_use_sync", "is_using_sync");
}
AnimationNodeBlend3::AnimationNodeBlend3() {
+ blend_amount = "blend_amount";
add_input("-blend");
add_input("in");
add_input("+blend");
sync = false;
- amount = 0;
}
/////////////////////////////////
-void AnimationNodeTimeScale::set_scale(float p_scale) {
- scale = p_scale;
+void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, scale, PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"));
}
-
-float AnimationNodeTimeScale::get_scale() const {
- return scale;
+Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
+ return 1.0; //initial timescale
}
String AnimationNodeTimeScale::get_caption() const {
@@ -544,6 +540,7 @@ String AnimationNodeTimeScale::get_caption() const {
float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
+ float scale = get_parameter(this->scale);
if (p_seek) {
return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
} else {
@@ -552,25 +549,19 @@ float AnimationNodeTimeScale::process(float p_time, bool p_seek) {
}
void AnimationNodeTimeScale::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_scale", "scale"), &AnimationNodeTimeScale::set_scale);
- ClassDB::bind_method(D_METHOD("get_scale"), &AnimationNodeTimeScale::get_scale);
-
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,32,0.01,or_greater"), "set_scale", "get_scale");
}
AnimationNodeTimeScale::AnimationNodeTimeScale() {
+ scale = "scale";
add_input("in");
- scale = 1.0;
}
////////////////////////////////////
-void AnimationNodeTimeSeek::set_seek_pos(float p_seek_pos) {
- seek_pos = p_seek_pos;
+void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::REAL, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
}
-
-float AnimationNodeTimeSeek::get_seek_pos() const {
- return seek_pos;
+Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
+ return 1.0; //initial timescale
}
String AnimationNodeTimeSeek::get_caption() const {
@@ -579,11 +570,12 @@ String AnimationNodeTimeSeek::get_caption() const {
float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
+ float seek_pos = get_parameter(this->seek_pos);
if (p_seek) {
return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false);
} else if (seek_pos >= 0) {
float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false);
- seek_pos = -1;
+ set_parameter(this->seek_pos, -1.0); //reset
_change_notify("seek_pos");
return ret;
} else {
@@ -592,19 +584,41 @@ float AnimationNodeTimeSeek::process(float p_time, bool p_seek) {
}
void AnimationNodeTimeSeek::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_seek_pos", "seek_pos"), &AnimationNodeTimeSeek::set_seek_pos);
- ClassDB::bind_method(D_METHOD("get_seek_pos"), &AnimationNodeTimeSeek::get_seek_pos);
-
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "seek_pos", PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"), "set_seek_pos", "get_seek_pos");
}
+
AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
add_input("in");
- seek_pos = -1;
+ seek_pos = "seek_position";
}
/////////////////////////////////////////////////
+void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
+
+ String anims;
+ for (int i = 0; i < enabled_inputs; i++) {
+ if (i > 0) {
+ anims += ",";
+ }
+ anims += inputs[i].name;
+ }
+
+ r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
+ r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0));
+ r_list->push_back(PropertyInfo(Variant::REAL, prev_xfading, PROPERTY_HINT_NONE, "", 0));
+}
+Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
+ if (p_parameter == time || p_parameter == prev_xfading) {
+ return 0.0;
+ } else if (p_parameter == prev || p_parameter == prev_current) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
String AnimationNodeTransition::get_caption() const {
return "Transition";
}
@@ -650,18 +664,12 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
-void AnimationNodeTransition::set_current(int p_current) {
-
- if (current == p_current)
- return;
- ERR_FAIL_INDEX(p_current, enabled_inputs);
-
+#if 0
Ref<AnimationNodeBlendTree> tree = get_parent();
if (tree.is_valid() && current >= 0) {
prev = current;
- prev_xfading = xfade;
- prev_time = time;
+ prev_xfading = xfade;
time = 0;
current = p_current;
switched = true;
@@ -669,11 +677,8 @@ void AnimationNodeTransition::set_current(int p_current) {
} else {
current = p_current;
}
-}
+#endif
-int AnimationNodeTransition::get_current() const {
- return current;
-}
void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
xfade = p_fade;
}
@@ -684,9 +689,34 @@ float AnimationNodeTransition::get_cross_fade_time() const {
float AnimationNodeTransition::process(float p_time, bool p_seek) {
+ int current = get_parameter(this->current);
+ int prev = get_parameter(this->prev);
+ int prev_current = get_parameter(this->prev_current);
+
+ float time = get_parameter(this->time);
+ float prev_xfading = get_parameter(this->prev_xfading);
+
+ bool switched = current != prev_current;
+
+ if (switched) {
+ set_parameter(this->prev_current, current);
+ set_parameter(this->prev, prev_current);
+
+ prev = prev_current;
+ prev_xfading = xfade;
+ time = 0;
+ switched = true;
+ }
+
+ if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) {
+ return 0;
+ }
+
+ float rem = 0;
+
if (prev < 0) { // process current animation, check for transition
- float rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
+ rem = blend_input(current, p_time, p_seek, 1.0, FILTER_IGNORE, false);
if (p_seek)
time = p_time;
@@ -695,16 +725,13 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
if (inputs[current].auto_advance && rem <= xfade) {
- set_current((current + 1) % enabled_inputs);
+ set_parameter(this->current, (current + 1) % enabled_inputs);
}
- return rem;
} else { // cross-fading from prev to current
float blend = xfade ? (prev_xfading / xfade) : 1;
- float rem;
-
if (!p_seek && switched) { //just switched, seek to start of current
rem = blend_input(current, 0, true, 1.0 - blend, FILTER_IGNORE, false);
@@ -723,28 +750,19 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) {
time += p_time;
prev_xfading -= p_time;
if (prev_xfading < 0) {
- prev = -1;
+ set_parameter(this->prev, -1);
}
}
-
- return rem;
}
+
+ set_parameter(this->time, time);
+ set_parameter(this->prev_xfading, prev_xfading);
+
+ return rem;
}
void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
- if (property.name == "current" && enabled_inputs > 0) {
- property.hint = PROPERTY_HINT_ENUM;
- String anims;
- for (int i = 0; i < enabled_inputs; i++) {
- if (i > 0) {
- anims += ",";
- }
- anims += inputs[i].name;
- }
- property.hint_string = anims;
- }
-
if (property.name.begins_with("input_")) {
String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
if (n != "count") {
@@ -769,14 +787,10 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
- ClassDB::bind_method(D_METHOD("set_current", "index"), &AnimationNodeTransition::set_current);
- ClassDB::bind_method(D_METHOD("get_current"), &AnimationNodeTransition::get_current);
-
ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "current", PROPERTY_HINT_RANGE, "0,64,1"), "set_current", "get_current");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01"), "set_cross_fade_time", "get_cross_fade_time");
for (int i = 0; i < MAX_INPUTS; i++) {
@@ -786,13 +800,15 @@ void AnimationNodeTransition::_bind_methods() {
}
AnimationNodeTransition::AnimationNodeTransition() {
+
+ prev_xfading = "prev_xfading";
+ prev = "prev";
+ time = "time";
+ current = "current";
+ prev_current = "prev_current";
+ ;
+
enabled_inputs = 0;
- xfade = 0;
- current = -1;
- prev = -1;
- prev_time = 0;
- prev_xfading = 0;
- switched = false;
for (int i = 0; i < MAX_INPUTS; i++) {
inputs[i].auto_advance = false;
inputs[i].name = itos(i + 1);
@@ -814,69 +830,102 @@ AnimationNodeOutput::AnimationNodeOutput() {
}
///////////////////////////////////////////////////////
-void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node) {
+void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
ERR_FAIL_COND(nodes.has(p_name));
ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
- ERR_FAIL_COND(p_node->get_tree() != NULL);
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(String(p_name).find("/") != -1);
- nodes[p_name] = p_node;
- p_node->set_parent(this);
- p_node->set_tree(get_tree());
+ Node n;
+ n.node = p_node;
+ n.position = p_position;
+ n.connections.resize(n.node->get_input_count());
+ nodes[p_name] = n;
emit_changed();
+ emit_signal("tree_changed");
+
+ p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+ p_node->connect("changed", this, "_node_changed", varray(p_name), CONNECT_REFERENCE_COUNTED);
}
Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) const {
ERR_FAIL_COND_V(!nodes.has(p_name), Ref<AnimationNode>());
- return nodes[p_name];
+ return nodes[p_name].node;
}
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- if (E->get() == p_node) {
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ if (E->get().node == p_node) {
return E->key();
}
}
ERR_FAIL_V(StringName());
}
+
+void AnimationNodeBlendTree::set_node_position(const StringName &p_node, const Vector2 &p_position) {
+ ERR_FAIL_COND(!nodes.has(p_node));
+ nodes[p_node].position = p_position;
+}
+
+Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) const {
+ ERR_FAIL_COND_V(!nodes.has(p_node), Vector2());
+ return nodes[p_node].position;
+}
+
+void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ Vector<StringName> ns;
+
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ ns.push_back(E->key());
+ }
+
+ ns.sort_custom<StringName::AlphCompare>();
+
+ for (int i = 0; i < ns.size(); i++) {
+ ChildNode cn;
+ cn.name = ns[i];
+ cn.node = nodes[cn.name].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
bool AnimationNodeBlendTree::has_node(const StringName &p_name) const {
return nodes.has(p_name);
}
+Vector<StringName> AnimationNodeBlendTree::get_node_connection_array(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!nodes.has(p_name), Vector<StringName>());
+ return nodes[p_name].connections;
+}
void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
ERR_FAIL_COND(!nodes.has(p_name));
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); //can't delete output
{
- //erase node connections
- Ref<AnimationNode> node = nodes[p_name];
- for (int i = 0; i < node->get_input_count(); i++) {
- node->set_input_connection(i, StringName());
- }
- node->set_parent(NULL);
- node->set_tree(NULL);
+ Ref<AnimationNode> node = nodes[p_name].node;
+ node->disconnect("tree_changed", this, "_tree_changed");
+ node->disconnect("changed", this, "_node_changed");
}
nodes.erase(p_name);
//erase connections to name
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- if (node->get_input_connection(i) == p_name) {
- node->set_input_connection(i, StringName());
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ if (E->get().connections[i] == p_name) {
+ E->get().connections.write[i] = StringName();
}
}
}
emit_changed();
+ emit_signal("tree_changed");
}
void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringName &p_new_name) {
@@ -886,18 +935,24 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_new_name == SceneStringNames::get_singleton()->output);
+ nodes[p_name].node->disconnect("changed", this, "_node_changed");
+
nodes[p_new_name] = nodes[p_name];
nodes.erase(p_name);
//rename connections
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- if (node->get_input_connection(i) == p_name) {
- node->set_input_connection(i, p_new_name);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ if (E->get().connections[i] == p_name) {
+ E->get().connections.write[i] = p_new_name;
}
}
}
+ //connection must be done with new name
+ nodes[p_new_name].node->connect("changed", this, "_node_changed", varray(p_new_name), CONNECT_REFERENCE_COUNTED);
+
+ emit_signal("tree_changed");
}
void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) {
@@ -907,18 +962,18 @@ void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_
ERR_FAIL_COND(p_output_node == SceneStringNames::get_singleton()->output);
ERR_FAIL_COND(p_input_node == p_output_node);
- Ref<AnimationNode> input = nodes[p_input_node];
- ERR_FAIL_INDEX(p_input_index, input->get_input_count());
+ Ref<AnimationNode> input = nodes[p_input_node].node;
+ ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- StringName output = node->get_input_connection(i);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ StringName output = E->get().connections[i];
ERR_FAIL_COND(output == p_output_node);
}
}
- input->set_input_connection(p_input_index, p_output_node);
+ nodes[p_input_node].connections.write[p_input_index] = p_output_node;
+
emit_changed();
}
@@ -926,20 +981,10 @@ void AnimationNodeBlendTree::disconnect_node(const StringName &p_node, int p_inp
ERR_FAIL_COND(!nodes.has(p_node));
- Ref<AnimationNode> input = nodes[p_node];
- ERR_FAIL_INDEX(p_input_index, input->get_input_count());
+ Ref<AnimationNode> input = nodes[p_node].node;
+ ERR_FAIL_INDEX(p_input_index, nodes[p_node].connections.size());
- input->set_input_connection(p_input_index, StringName());
-}
-
-float AnimationNodeBlendTree::get_connection_activity(const StringName &p_input_node, int p_input_index) const {
-
- ERR_FAIL_COND_V(!nodes.has(p_input_node), 0);
-
- Ref<AnimationNode> input = nodes[p_input_node];
- ERR_FAIL_INDEX_V(p_input_index, input->get_input_count(), 0);
-
- return input->get_input_activity(p_input_index);
+ nodes[p_node].connections.write[p_input_index] = StringName();
}
AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node) const {
@@ -956,20 +1001,19 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
return CONNECTION_ERROR_SAME_NODE;
}
- Ref<AnimationNode> input = nodes[p_input_node];
+ Ref<AnimationNode> input = nodes[p_input_node].node;
- if (p_input_index < 0 || p_input_index >= input->get_input_count()) {
+ if (p_input_index < 0 || p_input_index >= nodes[p_input_node].connections.size()) {
return CONNECTION_ERROR_NO_INPUT_INDEX;
}
- if (input->get_input_connection(p_input_index) != StringName()) {
+ if (nodes[p_input_node].connections[p_input_index] != StringName()) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- StringName output = node->get_input_connection(i);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ StringName output = E->get().connections[i];
if (output == p_output_node) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
@@ -980,10 +1024,9 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- for (int i = 0; i < node->get_input_count(); i++) {
- StringName output = node->get_input_connection(i);
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().connections.size(); i++) {
+ StringName output = E->get().connections[i];
if (output != StringName()) {
NodeConnection nc;
nc.input_node = E->key();
@@ -1001,13 +1044,13 @@ String AnimationNodeBlendTree::get_caption() const {
float AnimationNodeBlendTree::process(float p_time, bool p_seek) {
- Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output];
- return blend_node(output, p_time, p_seek, 1.0);
+ Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
+ return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, 1.0);
}
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
r_list->push_back(E->key());
}
}
@@ -1022,14 +1065,8 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const {
return graph_offset;
}
-void AnimationNodeBlendTree::set_tree(AnimationTree *p_player) {
-
- AnimationNode::set_tree(p_player);
-
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- Ref<AnimationNode> node = E->get();
- node->set_tree(p_player);
- }
+Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
+ return get_node(p_name);
}
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
@@ -1051,7 +1088,7 @@ bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_val
if (what == "position") {
if (nodes.has(node_name)) {
- nodes[node_name]->set_position(p_value);
+ nodes[node_name].position = p_value;
}
return true;
}
@@ -1078,7 +1115,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
if (what == "node") {
if (nodes.has(node_name)) {
- r_ret = nodes[node_name];
+ r_ret = nodes[node_name].node;
return true;
}
}
@@ -1086,7 +1123,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
if (what == "position") {
if (nodes.has(node_name)) {
- r_ret = nodes[node_name]->get_position();
+ r_ret = nodes[node_name].position;
return true;
}
}
@@ -1113,7 +1150,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
+ for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
names.push_back(E->key());
}
names.sort_custom<StringName::AlphCompare>();
@@ -1121,7 +1158,7 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
String name = E->get();
if (name != "output") {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
@@ -1129,9 +1166,19 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeBlendTree::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
+void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
+
+ ERR_FAIL_COND(!nodes.has(p_node));
+ nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
+}
+
void AnimationNodeBlendTree::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeBlendTree::add_node);
+ ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeBlendTree::add_node, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeBlendTree::get_node);
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeBlendTree::remove_node);
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeBlendTree::rename_node);
@@ -1139,9 +1186,15 @@ void AnimationNodeBlendTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect_node", "input_node", "input_index", "output_node"), &AnimationNodeBlendTree::connect_node);
ClassDB::bind_method(D_METHOD("disconnect_node", "input_node", "input_index"), &AnimationNodeBlendTree::disconnect_node);
+ ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeBlendTree::set_node_position);
+ ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeBlendTree::get_node_position);
+
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeBlendTree::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeBlendTree::get_graph_offset);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendTree::_tree_changed);
+ ClassDB::bind_method(D_METHOD("_node_changed", "node"), &AnimationNodeBlendTree::_node_changed);
+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset");
BIND_CONSTANT(CONNECTION_OK);
@@ -1156,15 +1209,12 @@ AnimationNodeBlendTree::AnimationNodeBlendTree() {
Ref<AnimationNodeOutput> output;
output.instance();
- output->set_position(Vector2(300, 150));
- output->set_parent(this);
- nodes["output"] = output;
+ Node n;
+ n.node = output;
+ n.position = Vector2(300, 150);
+ n.connections.resize(1);
+ nodes["output"] = n;
}
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
-
- for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) {
- E->get()->set_parent(NULL);
- E->get()->set_tree(NULL);
- }
}
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index e86cc2e823..7bf2917c1e 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -20,6 +20,8 @@ protected:
static void _bind_methods();
public:
+ static Vector<String> (*get_editable_animation_list)();
+
virtual String get_caption() const;
virtual float process(float p_time, bool p_seek);
@@ -41,8 +43,6 @@ public:
};
private:
- bool active;
- bool do_start;
float fade_in;
float fade_out;
@@ -51,15 +51,25 @@ private:
float autorestart_random_delay;
MixMode mix;
- float time;
- float remaining;
- float autorestart_remaining;
bool sync;
+ /* bool active;
+ bool do_start;
+ float time;
+ float remaining;*/
+
+ StringName active;
+ StringName prev_active;
+ StringName time;
+ StringName remaining;
+
protected:
static void _bind_methods();
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
void set_fadein_time(float p_time);
@@ -79,10 +89,6 @@ public:
void set_mix_mode(MixMode p_mix);
MixMode get_mix_mode() const;
- void start();
- void stop();
- bool is_active() const;
-
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -97,17 +103,17 @@ VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
class AnimationNodeAdd2 : public AnimationNode {
GDCLASS(AnimationNodeAdd2, AnimationNode);
- float amount;
+ StringName add_amount;
bool sync;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_amount(float p_amount);
- float get_amount() const;
+ virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -121,17 +127,17 @@ public:
class AnimationNodeAdd3 : public AnimationNode {
GDCLASS(AnimationNodeAdd3, AnimationNode);
- float amount;
+ StringName add_amount;
bool sync;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_amount(float p_amount);
- float get_amount() const;
+ virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -145,19 +151,19 @@ public:
class AnimationNodeBlend2 : public AnimationNode {
GDCLASS(AnimationNodeBlend2, AnimationNode);
- float amount;
+ StringName blend_amount;
bool sync;
protected:
static void _bind_methods();
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
virtual float process(float p_time, bool p_seek);
- void set_amount(float p_amount);
- float get_amount() const;
-
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -168,17 +174,17 @@ public:
class AnimationNodeBlend3 : public AnimationNode {
GDCLASS(AnimationNodeBlend3, AnimationNode);
- float amount;
+ StringName blend_amount;
bool sync;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_amount(float p_amount);
- float get_amount() const;
+ virtual String get_caption() const;
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -190,16 +196,16 @@ public:
class AnimationNodeTimeScale : public AnimationNode {
GDCLASS(AnimationNodeTimeScale, AnimationNode);
- float scale;
+ StringName scale;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_scale(float p_scale);
- float get_scale() const;
+ virtual String get_caption() const;
float process(float p_time, bool p_seek);
@@ -209,16 +215,16 @@ public:
class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
- float seek_pos;
+ StringName seek_pos;
protected:
static void _bind_methods();
public:
- virtual String get_caption() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
- void set_seek_pos(float p_sec);
- float get_seek_pos() const;
+ virtual String get_caption() const;
float process(float p_time, bool p_seek);
@@ -241,13 +247,18 @@ class AnimationNodeTransition : public AnimationNode {
InputData inputs[MAX_INPUTS];
int enabled_inputs;
- float prev_time;
+ /*
float prev_xfading;
int prev;
- bool switched;
-
float time;
int current;
+ int prev_current; */
+
+ StringName prev_xfading;
+ StringName prev;
+ StringName time;
+ StringName current;
+ StringName prev_current;
float xfade;
@@ -258,6 +269,9 @@ protected:
void _validate_property(PropertyInfo &property) const;
public:
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
virtual String get_caption() const;
void set_enabled_inputs(int p_inputs);
@@ -269,9 +283,6 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
- void set_current(int p_current);
- int get_current() const;
-
void set_cross_fade_time(float p_fade);
float get_cross_fade_time() const;
@@ -293,10 +304,19 @@ public:
class AnimationNodeBlendTree : public AnimationRootNode {
GDCLASS(AnimationNodeBlendTree, AnimationRootNode)
- Map<StringName, Ref<AnimationNode> > nodes;
+ struct Node {
+ Ref<AnimationNode> node;
+ Vector2 position;
+ Vector<StringName> connections;
+ };
+
+ Map<StringName, Node> nodes;
Vector2 graph_offset;
+ void _tree_changed();
+ void _node_changed(const StringName &p_node);
+
protected:
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_value);
@@ -314,16 +334,21 @@ public:
//no need to check for cycles due to tree topology
};
- void add_node(const StringName &p_name, Ref<AnimationNode> p_node);
+ void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
bool has_node(const StringName &p_name) const;
StringName get_node_name(const Ref<AnimationNode> &p_node) const;
+ Vector<StringName> get_node_connection_array(const StringName &p_name) const;
+
+ void set_node_position(const StringName &p_node, const Vector2 &p_position);
+ Vector2 get_node_position(const StringName &p_node) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
void connect_node(const StringName &p_input_node, int p_input_index, const StringName &p_output_node);
void disconnect_node(const StringName &p_node, int p_input_index);
- float get_connection_activity(const StringName &p_input_node, int p_input_index) const;
struct NodeConnection {
StringName input_node;
@@ -342,7 +367,8 @@ public:
void set_graph_offset(const Vector2 &p_graph_offset);
Vector2 get_graph_offset() const;
- virtual void set_tree(AnimationTree *p_player);
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
+
AnimationNodeBlendTree();
~AnimationNodeBlendTree();
};
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index f478112a36..09c36eb081 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -20,6 +20,26 @@ bool AnimationNodeStateMachineTransition::has_auto_advance() const {
return auto_advance;
}
+void AnimationNodeStateMachineTransition::set_advance_condition(const StringName &p_condition) {
+ String cs = p_condition;
+ ERR_FAIL_COND(cs.find("/") != -1 || cs.find(":") != -1);
+ advance_condition = p_condition;
+ if (cs != String()) {
+ advance_condition_name = "conditions/" + cs;
+ } else {
+ advance_condition_name = StringName();
+ }
+ emit_signal("advance_condition_changed");
+}
+
+StringName AnimationNodeStateMachineTransition::get_advance_condition() const {
+ return advance_condition;
+}
+
+StringName AnimationNodeStateMachineTransition::get_advance_condition_name() const {
+ return advance_condition_name;
+}
+
void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) {
ERR_FAIL_COND(p_xfade < 0);
@@ -56,6 +76,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_advance", "auto_advance"), &AnimationNodeStateMachineTransition::set_auto_advance);
ClassDB::bind_method(D_METHOD("has_auto_advance"), &AnimationNodeStateMachineTransition::has_auto_advance);
+ ClassDB::bind_method(D_METHOD("set_advance_condition", "name"), &AnimationNodeStateMachineTransition::set_advance_condition);
+ ClassDB::bind_method(D_METHOD("get_advance_condition"), &AnimationNodeStateMachineTransition::get_advance_condition);
+
ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time);
@@ -67,6 +90,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,AtEnd"), "set_switch_mode", "get_switch_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "advance_condition"), "set_advance_condition", "get_advance_condition");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
@@ -74,6 +98,8 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
BIND_ENUM_CONSTANT(SWITCH_MODE_IMMEDIATE);
BIND_ENUM_CONSTANT(SWITCH_MODE_SYNC);
BIND_ENUM_CONSTANT(SWITCH_MODE_AT_END);
+
+ ADD_SIGNAL(MethodInfo("advance_condition_changed"));
}
AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
@@ -85,277 +111,240 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
priority = 1;
}
-///////////////////////////////////////////////////////
-void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node) {
-
- ERR_FAIL_COND(states.has(p_name));
- ERR_FAIL_COND(p_node.is_null());
- ERR_FAIL_COND(p_node->get_parent().is_valid());
- ERR_FAIL_COND(p_node->get_tree() != NULL);
- ERR_FAIL_COND(String(p_name).find("/") != -1);
- states[p_name] = p_node;
+////////////////////////////////////////////////////////
- p_node->set_parent(this);
- p_node->set_tree(get_tree());
+void AnimationNodeStateMachinePlayback::travel(const StringName &p_state) {
- emit_changed();
+ start_request_travel = true;
+ start_request = p_state;
+ stop_request = false;
}
-Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const {
-
- ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>());
-
- return states[p_name];
+void AnimationNodeStateMachinePlayback::start(const StringName &p_state) {
+ start_request_travel = false;
+ start_request = p_state;
+ stop_request = false;
}
+void AnimationNodeStateMachinePlayback::stop() {
-StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const {
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
- if (E->get() == p_node) {
- return E->key();
- }
- }
-
- ERR_FAIL_V(StringName());
+ stop_request = true;
}
-
-bool AnimationNodeStateMachine::has_node(const StringName &p_name) const {
- return states.has(p_name);
+bool AnimationNodeStateMachinePlayback::is_playing() const {
+ return playing;
+}
+StringName AnimationNodeStateMachinePlayback::get_current_node() const {
+ return current;
+}
+StringName AnimationNodeStateMachinePlayback::get_blend_from_node() const {
+ return fading_from;
+}
+Vector<StringName> AnimationNodeStateMachinePlayback::get_travel_path() const {
+ return path;
+}
+float AnimationNodeStateMachinePlayback::get_current_play_pos() const {
+ return pos_current;
+}
+float AnimationNodeStateMachinePlayback::get_current_length() const {
+ return len_current;
}
-void AnimationNodeStateMachine::remove_node(const StringName &p_name) {
-
- ERR_FAIL_COND(!states.has(p_name));
-
- {
- //erase node connections
- Ref<AnimationNode> node = states[p_name];
- for (int i = 0; i < node->get_input_count(); i++) {
- node->set_input_connection(i, StringName());
- }
- node->set_parent(NULL);
- node->set_tree(NULL);
- }
- states.erase(p_name);
- path.erase(p_name);
+bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *sm, const StringName &p_travel) {
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_name || transitions[i].to == p_name) {
- transitions.remove(i);
- i--;
- }
- }
+ ERR_FAIL_COND_V(!playing, false);
+ ERR_FAIL_COND_V(!sm->states.has(p_travel), false);
+ ERR_FAIL_COND_V(!sm->states.has(current), false);
- if (start_node == p_name) {
- start_node = StringName();
- }
+ path.clear(); //a new one will be needed
- if (end_node == p_name) {
- end_node = StringName();
- }
+ if (current == p_travel)
+ return true; //nothing to do
- if (playing && current == p_name) {
- stop();
- }
- emit_changed();
-}
+ loops_current = 0; // reset loops, so fade does not happen immediately
-void AnimationNodeStateMachine::rename_node(const StringName &p_name, const StringName &p_new_name) {
+ Vector2 current_pos = sm->states[current].position;
+ Vector2 target_pos = sm->states[p_travel].position;
- ERR_FAIL_COND(!states.has(p_name));
- ERR_FAIL_COND(states.has(p_new_name));
+ Map<StringName, AStarCost> cost_map;
- states[p_new_name] = states[p_name];
- states.erase(p_name);
+ List<int> open_list;
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_name) {
- transitions.write[i].from = p_new_name;
- }
+ //build open list
+ for (int i = 0; i < sm->transitions.size(); i++) {
+ if (sm->transitions[i].from == current) {
+ open_list.push_back(i);
+ float cost = sm->states[sm->transitions[i].to].position.distance_to(current_pos);
+ cost *= sm->transitions[i].transition->get_priority();
+ AStarCost ap;
+ ap.prev = current;
+ ap.distance = cost;
+ cost_map[sm->transitions[i].to] = ap;
- if (transitions[i].to == p_name) {
- transitions.write[i].to = p_new_name;
+ if (sm->transitions[i].to == p_travel) { //prematurely found it! :D
+ path.push_back(p_travel);
+ return true;
+ }
}
}
- if (start_node == p_name) {
- start_node = p_new_name;
- }
+ //begin astar
+ bool found_route = false;
+ while (!found_route) {
- if (end_node == p_name) {
- end_node = p_new_name;
- }
+ if (open_list.size() == 0) {
+ return false; //no path found
+ }
- if (playing && current == p_name) {
- current = p_new_name;
- }
+ //find the last cost transition
+ List<int>::Element *least_cost_transition = NULL;
+ float least_cost = 1e20;
- path.clear(); //clear path
-}
+ for (List<int>::Element *E = open_list.front(); E; E = E->next()) {
-void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
+ float cost = cost_map[sm->transitions[E->get()].to].distance;
+ cost += sm->states[sm->transitions[E->get()].to].position.distance_to(target_pos);
- List<StringName> nodes;
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
- nodes.push_back(E->key());
- }
- nodes.sort_custom<StringName::AlphCompare>();
+ if (cost < least_cost) {
+ least_cost_transition = E;
+ }
+ }
- for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
- r_nodes->push_back(E->get());
- }
-}
+ StringName transition_prev = sm->transitions[least_cost_transition->get()].from;
+ StringName transition = sm->transitions[least_cost_transition->get()].to;
-bool AnimationNodeStateMachine::has_transition(const StringName &p_from, const StringName &p_to) const {
+ for (int i = 0; i < sm->transitions.size(); i++) {
+ if (sm->transitions[i].from != transition || sm->transitions[i].to == transition_prev) {
+ continue; //not interested on those
+ }
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_from && transitions[i].to == p_to)
- return true;
- }
- return false;
-}
+ float distance = sm->states[sm->transitions[i].from].position.distance_to(sm->states[sm->transitions[i].to].position);
+ distance *= sm->transitions[i].transition->get_priority();
+ distance += cost_map[sm->transitions[i].from].distance;
-int AnimationNodeStateMachine::find_transition(const StringName &p_from, const StringName &p_to) const {
+ if (cost_map.has(sm->transitions[i].to)) {
+ //oh this was visited already, can we win the cost?
+ if (distance < cost_map[sm->transitions[i].to].distance) {
+ cost_map[sm->transitions[i].to].distance = distance;
+ cost_map[sm->transitions[i].to].prev = sm->transitions[i].from;
+ }
+ } else {
+ //add to open list
+ AStarCost ac;
+ ac.prev = sm->transitions[i].from;
+ ac.distance = distance;
+ cost_map[sm->transitions[i].to] = ac;
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_from && transitions[i].to == p_to)
- return i;
- }
- return -1;
-}
+ open_list.push_back(i);
-void AnimationNodeStateMachine::add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition) {
+ if (sm->transitions[i].to == p_travel) {
+ found_route = true;
+ break;
+ }
+ }
+ }
- ERR_FAIL_COND(p_from == p_to);
- ERR_FAIL_COND(!states.has(p_from));
- ERR_FAIL_COND(!states.has(p_to));
- ERR_FAIL_COND(p_transition.is_null());
+ if (found_route) {
+ break;
+ }
- for (int i = 0; i < transitions.size(); i++) {
- ERR_FAIL_COND(transitions[i].from == p_from && transitions[i].to == p_to);
+ open_list.erase(least_cost_transition);
}
- Transition tr;
- tr.from = p_from;
- tr.to = p_to;
- tr.transition = p_transition;
-
- transitions.push_back(tr);
-}
-
-Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_transition(int p_transition) const {
- ERR_FAIL_INDEX_V(p_transition, transitions.size(), Ref<AnimationNodeStateMachineTransition>());
- return transitions[p_transition].transition;
-}
-StringName AnimationNodeStateMachine::get_transition_from(int p_transition) const {
+ //make path
+ StringName at = p_travel;
+ while (at != current) {
+ path.push_back(at);
+ at = cost_map[at].prev;
+ }
- ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
- return transitions[p_transition].from;
-}
-StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const {
+ path.invert();
- ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
- return transitions[p_transition].to;
+ return true;
}
-int AnimationNodeStateMachine::get_transition_count() const {
-
- return transitions.size();
-}
-void AnimationNodeStateMachine::remove_transition(const StringName &p_from, const StringName &p_to) {
+float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, float p_time, bool p_seek) {
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == p_from && transitions[i].to == p_to) {
- transitions.remove(i);
- return;
+ //if not playing and it can restart, then restart
+ if (!playing && start_request == StringName()) {
+ if (!stop_request && sm->start_node) {
+ start(sm->start_node);
+ } else {
+ return 0;
}
}
- if (playing) {
- path.clear();
- }
-}
-
-void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) {
-
- transitions.remove(p_transition);
- if (playing) {
- path.clear();
+ if (playing && stop_request) {
+ stop_request = false;
+ playing = false;
+ return 0;
}
-}
-
-void AnimationNodeStateMachine::set_start_node(const StringName &p_node) {
-
- ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
- start_node = p_node;
-}
-
-String AnimationNodeStateMachine::get_start_node() const {
-
- return start_node;
-}
-
-void AnimationNodeStateMachine::set_end_node(const StringName &p_node) {
-
- ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
- end_node = p_node;
-}
-
-String AnimationNodeStateMachine::get_end_node() const {
-
- return end_node;
-}
-void AnimationNodeStateMachine::set_graph_offset(const Vector2 &p_offset) {
- graph_offset = p_offset;
-}
+ bool play_start = false;
-Vector2 AnimationNodeStateMachine::get_graph_offset() const {
- return graph_offset;
-}
+ if (start_request != StringName()) {
-float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
+ if (start_request_travel) {
+ if (!playing) {
+ start_request = StringName();
+ ERR_EXPLAIN("Can't travel to '" + String(start_request) + "' if state machine is not active.");
+ ERR_FAIL_V(0);
+ }
- //if not playing and it can restart, then restart
- if (!playing) {
- if (start_node) {
- start(start_node);
+ if (!_travel(sm, start_request)) {
+ //cant travel, then teleport
+ path.clear();
+ current = start_request;
+ }
} else {
- return 0;
+ path.clear();
+ current = start_request;
+ playing = true;
+ play_start = true;
}
+
+ start_request = StringName(); //clear start request
}
bool do_start = (p_seek && p_time == 0) || play_start || current == StringName();
if (do_start) {
- if (start_node != StringName() && p_seek && p_time == 0) {
- current = start_node;
+ if (sm->start_node != StringName() && p_seek && p_time == 0) {
+ current = sm->start_node;
}
- len_current = blend_node(states[current], 0, true, 1.0, FILTER_IGNORE, false);
+ len_current = sm->blend_node(current, sm->states[current].node, 0, true, 1.0, AnimationNode::FILTER_IGNORE, false);
pos_current = 0;
loops_current = 0;
play_start = false;
}
+ if (!sm->states.has(current)) {
+ playing = false; //current does not exist
+ current = StringName();
+ return 0;
+ }
float fade_blend = 1.0;
if (fading_from != StringName()) {
- if (!p_seek) {
- fading_pos += p_time;
- }
- fade_blend = MIN(1.0, fading_pos / fading_time);
- if (fade_blend >= 1.0) {
+ if (!sm->states.has(fading_from)) {
fading_from = StringName();
+ } else {
+ if (!p_seek) {
+ fading_pos += p_time;
+ }
+ fade_blend = MIN(1.0, fading_pos / fading_time);
+ if (fade_blend >= 1.0) {
+ fading_from = StringName();
+ }
}
}
- float rem = blend_node(states[current], p_time, p_seek, fade_blend, FILTER_IGNORE, false);
+ float rem = sm->blend_node(current, sm->states[current].node, p_time, p_seek, fade_blend, AnimationNode::FILTER_IGNORE, false);
if (fading_from != StringName()) {
- blend_node(states[fading_from], p_time, p_seek, 1.0 - fade_blend, FILTER_IGNORE, false);
+ sm->blend_node(current, sm->states[fading_from].node, p_time, p_seek, 1.0 - fade_blend, AnimationNode::FILTER_IGNORE, false);
}
//guess playback position
@@ -380,29 +369,39 @@ float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
if (path.size()) {
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == current && transitions[i].to == path[0]) {
- next_xfade = transitions[i].transition->get_xfade_time();
- switch_mode = transitions[i].transition->get_switch_mode();
+ for (int i = 0; i < sm->transitions.size(); i++) {
+ if (sm->transitions[i].from == current && sm->transitions[i].to == path[0]) {
+ next_xfade = sm->transitions[i].transition->get_xfade_time();
+ switch_mode = sm->transitions[i].transition->get_switch_mode();
next = path[0];
}
}
} else {
float priority_best = 1e20;
int auto_advance_to = -1;
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == current && transitions[i].transition->has_auto_advance()) {
+ for (int i = 0; i < sm->transitions.size(); i++) {
+
+ bool auto_advance = false;
+ if (sm->transitions[i].transition->has_auto_advance()) {
+ auto_advance = true;
+ }
+ StringName advance_condition_name = sm->transitions[i].transition->get_advance_condition_name();
+ if (advance_condition_name != StringName() && bool(sm->get_parameter(advance_condition_name))) {
+ auto_advance = true;
+ }
+
+ if (sm->transitions[i].from == current && sm->transitions[i].transition->has_auto_advance()) {
- if (transitions[i].transition->get_priority() < priority_best) {
+ if (sm->transitions[i].transition->get_priority() < priority_best) {
auto_advance_to = i;
}
}
}
if (auto_advance_to != -1) {
- next = transitions[auto_advance_to].to;
- next_xfade = transitions[auto_advance_to].transition->get_xfade_time();
- switch_mode = transitions[auto_advance_to].transition->get_switch_mode();
+ next = sm->transitions[auto_advance_to].to;
+ next_xfade = sm->transitions[auto_advance_to].transition->get_xfade_time();
+ switch_mode = sm->transitions[auto_advance_to].transition->get_switch_mode();
}
}
@@ -437,12 +436,12 @@ float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
}
current = next;
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
- len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false);
+ len_current = sm->blend_node(current, sm->states[current].node, 0, true, 0, AnimationNode::FILTER_IGNORE, false);
pos_current = MIN(pos_current, len_current);
- blend_node(states[current], pos_current, true, 0, FILTER_IGNORE, false);
+ sm->blend_node(current, sm->states[current].node, pos_current, true, 0, AnimationNode::FILTER_IGNORE, false);
} else {
- len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false);
+ len_current = sm->blend_node(current, sm->states[current].node, 0, true, 0, AnimationNode::FILTER_IGNORE, false);
pos_current = 0;
}
@@ -453,169 +452,321 @@ float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
//compute time left for transitions by using the end node
- if (end_node != StringName() && end_node != current) {
+ if (sm->end_node != StringName() && sm->end_node != current) {
- rem = blend_node(states[end_node], 0, true, 0, FILTER_IGNORE, false);
+ rem = sm->blend_node(current, sm->states[sm->end_node].node, 0, true, 0, AnimationNode::FILTER_IGNORE, false);
}
return rem;
}
-bool AnimationNodeStateMachine::travel(const StringName &p_state) {
- ERR_FAIL_COND_V(!playing, false);
- ERR_FAIL_COND_V(!states.has(p_state), false);
- ERR_FAIL_COND_V(!states.has(current), false);
+void AnimationNodeStateMachinePlayback::_bind_methods() {
- path.clear(); //a new one will be needed
+ ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachinePlayback::travel);
+ ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachinePlayback::start);
+ ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop);
+ ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing);
+ ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node);
+ ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::get_travel_path);
+}
- if (current == p_state)
- return true; //nothing to do
+AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
+ set_local_to_scene(true); //only one per instanced scene
- loops_current = 0; // reset loops, so fade does not happen immediately
+ playing = false;
+ len_current = 0;
+ fading_time = 0;
+ stop_request = false;
+}
- Vector2 current_pos = states[current]->get_position();
- Vector2 target_pos = states[p_state]->get_position();
+///////////////////////////////////////////////////////
- Map<StringName, AStarCost> cost_map;
+void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) const {
+ r_list->push_back(PropertyInfo(Variant::OBJECT, playback, PROPERTY_HINT_RESOURCE_TYPE, "AnimationNodeStateMachinePlayback", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ List<StringName> advance_conditions;
+ for (int i = 0; i < transitions.size(); i++) {
+ StringName ac = transitions[i].transition->get_advance_condition_name();
+ if (ac != StringName() && advance_conditions.find(ac) == NULL) {
+ advance_conditions.push_back(ac);
+ }
+ }
- List<int> open_list;
+ advance_conditions.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = advance_conditions.front(); E; E = E->next()) {
+ r_list->push_back(PropertyInfo(Variant::BOOL, E->get()));
+ }
+}
- //build open list
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from == current) {
- open_list.push_back(i);
- float cost = states[transitions[i].to]->get_position().distance_to(current_pos);
- cost *= transitions[i].transition->get_priority();
- AStarCost ap;
- ap.prev = current;
- ap.distance = cost;
- cost_map[transitions[i].to] = ap;
+Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const {
- if (transitions[i].to == p_state) { //prematurely found it! :D
- path.push_back(p_state);
- return true;
- }
- }
+ if (p_parameter == playback) {
+ Ref<AnimationNodeStateMachinePlayback> p;
+ p.instance();
+ return p;
+ } else {
+ return false; //advance condition
}
+}
- //begin astar
- bool found_route = false;
- while (!found_route) {
+void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position) {
- if (open_list.size() == 0) {
- return false; //no path found
+ ERR_FAIL_COND(states.has(p_name));
+ ERR_FAIL_COND(p_node.is_null());
+ ERR_FAIL_COND(String(p_name).find("/") != -1);
+
+ State state;
+ state.node = p_node;
+ state.position = p_position;
+
+ states[p_name] = state;
+
+ emit_changed();
+ emit_signal("tree_changed");
+
+ p_node->connect("tree_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+}
+
+Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>());
+
+ return states[p_name].node;
+}
+
+StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const {
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
+ if (E->get().node == p_node) {
+ return E->key();
}
+ }
- //find the last cost transition
- List<int>::Element *least_cost_transition = NULL;
- float least_cost = 1e20;
+ ERR_FAIL_V(StringName());
+}
- for (List<int>::Element *E = open_list.front(); E; E = E->next()) {
+void AnimationNodeStateMachine::get_child_nodes(List<ChildNode> *r_child_nodes) {
+ Vector<StringName> nodes;
- float cost = cost_map[transitions[E->get()].to].distance;
- cost += states[transitions[E->get()].to]->get_position().distance_to(target_pos);
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
+ nodes.push_back(E->key());
+ }
- if (cost < least_cost) {
- least_cost_transition = E;
- }
+ nodes.sort_custom<StringName::AlphCompare>();
+
+ for (int i = 0; i < nodes.size(); i++) {
+ ChildNode cn;
+ cn.name = nodes[i];
+ cn.node = states[cn.name].node;
+ r_child_nodes->push_back(cn);
+ }
+}
+
+bool AnimationNodeStateMachine::has_node(const StringName &p_name) const {
+ return states.has(p_name);
+}
+void AnimationNodeStateMachine::remove_node(const StringName &p_name) {
+
+ ERR_FAIL_COND(!states.has(p_name));
+
+ {
+ Ref<AnimationNode> node = states[p_name].node;
+ node->disconnect("tree_changed", this, "_tree_changed");
+ }
+
+ states.erase(p_name);
+ //path.erase(p_name);
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_name || transitions[i].to == p_name) {
+ transitions.write[i].transition->disconnect("advance_condition_changed", this, "_tree_changed");
+ transitions.remove(i);
+ i--;
}
+ }
- StringName transition_prev = transitions[least_cost_transition->get()].from;
- StringName transition = transitions[least_cost_transition->get()].to;
+ if (start_node == p_name) {
+ start_node = StringName();
+ }
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].from != transition || transitions[i].to == transition_prev) {
- continue; //not interested on those
- }
+ if (end_node == p_name) {
+ end_node = StringName();
+ }
- float distance = states[transitions[i].from]->get_position().distance_to(states[transitions[i].to]->get_position());
- distance *= transitions[i].transition->get_priority();
- distance += cost_map[transitions[i].from].distance;
+ /*if (playing && current == p_name) {
+ stop();
+ }*/
- if (cost_map.has(transitions[i].to)) {
- //oh this was visited already, can we win the cost?
- if (distance < cost_map[transitions[i].to].distance) {
- cost_map[transitions[i].to].distance = distance;
- cost_map[transitions[i].to].prev = transitions[i].from;
- }
- } else {
- //add to open list
- AStarCost ac;
- ac.prev = transitions[i].from;
- ac.distance = distance;
- cost_map[transitions[i].to] = ac;
+ emit_changed();
+ emit_signal("tree_changed");
+}
- open_list.push_back(i);
+void AnimationNodeStateMachine::rename_node(const StringName &p_name, const StringName &p_new_name) {
- if (transitions[i].to == p_state) {
- found_route = true;
- break;
- }
- }
+ ERR_FAIL_COND(!states.has(p_name));
+ ERR_FAIL_COND(states.has(p_new_name));
+
+ states[p_new_name] = states[p_name];
+ states.erase(p_name);
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_name) {
+ transitions.write[i].from = p_new_name;
}
- if (found_route) {
- break;
+ if (transitions[i].to == p_name) {
+ transitions.write[i].to = p_new_name;
}
+ }
- open_list.erase(least_cost_transition);
+ if (start_node == p_name) {
+ start_node = p_new_name;
}
- //make path
- StringName at = p_state;
- while (at != current) {
- path.push_back(at);
- at = cost_map[at].prev;
+ if (end_node == p_name) {
+ end_node = p_new_name;
}
- path.invert();
+ /*if (playing && current == p_name) {
+ current = p_new_name;
+ }*/
- return true;
+ //path.clear(); //clear path
+ emit_signal("tree_changed");
}
-void AnimationNodeStateMachine::start(const StringName &p_state) {
+void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
- ERR_FAIL_COND(!states.has(p_state));
- path.clear();
- current = p_state;
- playing = true;
- play_start = true;
+ List<StringName> nodes;
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
+ nodes.push_back(E->key());
+ }
+ nodes.sort_custom<StringName::AlphCompare>();
+
+ for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) {
+ r_nodes->push_back(E->get());
+ }
}
-void AnimationNodeStateMachine::stop() {
- playing = false;
- play_start = false;
- current = StringName();
+
+bool AnimationNodeStateMachine::has_transition(const StringName &p_from, const StringName &p_to) const {
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_from && transitions[i].to == p_to)
+ return true;
+ }
+ return false;
}
-bool AnimationNodeStateMachine::is_playing() const {
- return playing;
+int AnimationNodeStateMachine::find_transition(const StringName &p_from, const StringName &p_to) const {
+
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_from && transitions[i].to == p_to)
+ return i;
+ }
+ return -1;
}
-StringName AnimationNodeStateMachine::get_current_node() const {
- if (!playing) {
- return StringName();
+
+void AnimationNodeStateMachine::add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition) {
+
+ ERR_FAIL_COND(p_from == p_to);
+ ERR_FAIL_COND(!states.has(p_from));
+ ERR_FAIL_COND(!states.has(p_to));
+ ERR_FAIL_COND(p_transition.is_null());
+
+ for (int i = 0; i < transitions.size(); i++) {
+ ERR_FAIL_COND(transitions[i].from == p_from && transitions[i].to == p_to);
}
- return current;
+ Transition tr;
+ tr.from = p_from;
+ tr.to = p_to;
+ tr.transition = p_transition;
+
+ tr.transition->connect("advance_condition_changed", this, "_tree_changed", varray(), CONNECT_REFERENCE_COUNTED);
+
+ transitions.push_back(tr);
+}
+
+Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_transition(int p_transition) const {
+ ERR_FAIL_INDEX_V(p_transition, transitions.size(), Ref<AnimationNodeStateMachineTransition>());
+ return transitions[p_transition].transition;
}
+StringName AnimationNodeStateMachine::get_transition_from(int p_transition) const {
+
+ ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
+ return transitions[p_transition].from;
+}
+StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const {
+
+ ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName());
+ return transitions[p_transition].to;
+}
+
+int AnimationNodeStateMachine::get_transition_count() const {
+
+ return transitions.size();
+}
+void AnimationNodeStateMachine::remove_transition(const StringName &p_from, const StringName &p_to) {
-StringName AnimationNodeStateMachine::get_blend_from_node() const {
- if (!playing) {
- return StringName();
+ for (int i = 0; i < transitions.size(); i++) {
+ if (transitions[i].from == p_from && transitions[i].to == p_to) {
+ transitions.write[i].transition->disconnect("advance_condition_changed", this, "_tree_changed");
+ transitions.remove(i);
+ return;
+ }
}
- return fading_from;
+ /*if (playing) {
+ path.clear();
+ }*/
}
-float AnimationNodeStateMachine::get_current_play_pos() const {
- return pos_current;
+void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) {
+
+ ERR_FAIL_INDEX(p_transition, transitions.size());
+ transitions.write[p_transition].transition->disconnect("advance_condition_changed", this, "_tree_changed");
+ transitions.remove(p_transition);
+ /*if (playing) {
+ path.clear();
+ }*/
}
-float AnimationNodeStateMachine::get_current_length() const {
- return len_current;
+
+void AnimationNodeStateMachine::set_start_node(const StringName &p_node) {
+
+ ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
+ start_node = p_node;
}
-Vector<StringName> AnimationNodeStateMachine::get_travel_path() const {
- return path;
+String AnimationNodeStateMachine::get_start_node() const {
+
+ return start_node;
+}
+
+void AnimationNodeStateMachine::set_end_node(const StringName &p_node) {
+
+ ERR_FAIL_COND(p_node != StringName() && !states.has(p_node));
+ end_node = p_node;
+}
+
+String AnimationNodeStateMachine::get_end_node() const {
+
+ return end_node;
+}
+
+void AnimationNodeStateMachine::set_graph_offset(const Vector2 &p_offset) {
+ graph_offset = p_offset;
+}
+
+Vector2 AnimationNodeStateMachine::get_graph_offset() const {
+ return graph_offset;
+}
+
+float AnimationNodeStateMachine::process(float p_time, bool p_seek) {
+
+ Ref<AnimationNodeStateMachinePlayback> playback = get_parameter(this->playback);
+ ERR_FAIL_COND_V(playback.is_null(), 0.0);
+
+ return playback->process(this, p_time, p_seek);
}
+
String AnimationNodeStateMachine::get_caption() const {
return "StateMachine";
}
@@ -623,14 +774,8 @@ String AnimationNodeStateMachine::get_caption() const {
void AnimationNodeStateMachine::_notification(int p_what) {
}
-void AnimationNodeStateMachine::set_tree(AnimationTree *p_player) {
-
- AnimationNode::set_tree(p_player);
-
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
- Ref<AnimationRootNode> node = E->get();
- node->set_tree(p_player);
- }
+Ref<AnimationNode> AnimationNodeStateMachine::get_child_by_name(const StringName &p_name) {
+ return get_node(p_name);
}
bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_value) {
@@ -651,7 +796,7 @@ bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_
if (what == "position") {
if (states.has(node_name)) {
- states[node_name]->set_position(p_value);
+ states[node_name].position = p_value;
}
return true;
}
@@ -687,7 +832,7 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
if (what == "node") {
if (states.has(node_name)) {
- r_ret = states[node_name];
+ r_ret = states[node_name].node;
return true;
}
}
@@ -695,7 +840,7 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
if (what == "position") {
if (states.has(node_name)) {
- r_ret = states[node_name]->get_position();
+ r_ret = states[node_name].position;
return true;
}
}
@@ -727,14 +872,14 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
- for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) {
+ for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
names.push_back(E->key());
}
names.sort_custom<StringName::AlphCompare>();
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
String name = E->get();
- p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
@@ -744,16 +889,34 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c
p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
+void AnimationNodeStateMachine::set_node_position(const StringName &p_name, const Vector2 &p_position) {
+ ERR_FAIL_COND(!states.has(p_name));
+ states[p_name].position = p_position;
+}
+
+Vector2 AnimationNodeStateMachine::get_node_position(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!states.has(p_name), Vector2());
+ return states[p_name].position;
+}
+
+void AnimationNodeStateMachine::_tree_changed() {
+ emit_signal("tree_changed");
+}
+
void AnimationNodeStateMachine::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeStateMachine::add_node);
+ ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeStateMachine::add_node, DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node);
ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeStateMachine::remove_node);
ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeStateMachine::rename_node);
ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeStateMachine::has_node);
ClassDB::bind_method(D_METHOD("get_node_name", "node"), &AnimationNodeStateMachine::get_node_name);
- ClassDB::bind_method(D_METHOD("has_transition", "from", "to"), &AnimationNodeStateMachine::add_transition);
+ ClassDB::bind_method(D_METHOD("set_node_position", "name", "position"), &AnimationNodeStateMachine::set_node_position);
+ ClassDB::bind_method(D_METHOD("get_node_position", "name"), &AnimationNodeStateMachine::get_node_position);
+
+ ClassDB::bind_method(D_METHOD("has_transition", "from", "to"), &AnimationNodeStateMachine::has_transition);
ClassDB::bind_method(D_METHOD("add_transition", "from", "to", "transition"), &AnimationNodeStateMachine::add_transition);
ClassDB::bind_method(D_METHOD("get_transition", "idx"), &AnimationNodeStateMachine::get_transition);
ClassDB::bind_method(D_METHOD("get_transition_from", "idx"), &AnimationNodeStateMachine::get_transition_from);
@@ -771,20 +934,10 @@ void AnimationNodeStateMachine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_graph_offset", "name"), &AnimationNodeStateMachine::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset);
- ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachine::travel);
- ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachine::start);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachine::stop);
- ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachine::is_playing);
- ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachine::get_current_node);
- ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachine::get_travel_path);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeStateMachine::_tree_changed);
}
AnimationNodeStateMachine::AnimationNodeStateMachine() {
- play_start = false;
-
- playing = false;
- len_current = 0;
-
- fading_time = 0;
+ playback = "playback";
}
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index e7357e09ea..5d633d6334 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -15,6 +15,8 @@ public:
private:
SwitchMode switch_mode;
bool auto_advance;
+ StringName advance_condition;
+ StringName advance_condition_name;
float xfade;
bool disabled;
int priority;
@@ -29,6 +31,11 @@ public:
void set_auto_advance(bool p_enable);
bool has_auto_advance() const;
+ void set_advance_condition(const StringName &p_condition);
+ StringName get_advance_condition() const;
+
+ StringName get_advance_condition_name() const;
+
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
@@ -43,39 +50,24 @@ public:
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode)
-class AnimationNodeStateMachine : public AnimationRootNode {
-
- GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
+class AnimationNodeStateMachine;
-private:
- Map<StringName, Ref<AnimationRootNode> > states;
+class AnimationNodeStateMachinePlayback : public Resource {
+ GDCLASS(AnimationNodeStateMachinePlayback, Resource);
- struct Transition {
-
- StringName from;
- StringName to;
- Ref<AnimationNodeStateMachineTransition> transition;
- };
+ friend class AnimationNodeStateMachine;
struct AStarCost {
float distance;
StringName prev;
};
- Vector<Transition> transitions;
-
float len_total;
float len_current;
float pos_current;
int loops_current;
- bool play_start;
- StringName start_node;
- StringName end_node;
-
- Vector2 graph_offset;
-
StringName current;
StringName fading_from;
@@ -85,6 +77,63 @@ private:
Vector<StringName> path;
bool playing;
+ StringName start_request;
+ bool start_request_travel;
+ bool stop_request;
+
+ bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
+
+ float process(AnimationNodeStateMachine *p_state_machine, float p_time, bool p_seek);
+
+protected:
+ static void _bind_methods();
+
+public:
+ void travel(const StringName &p_state);
+ void start(const StringName &p_state);
+ void stop();
+ bool is_playing() const;
+ StringName get_current_node() const;
+ StringName get_blend_from_node() const;
+ Vector<StringName> get_travel_path() const;
+ float get_current_play_pos() const;
+ float get_current_length() const;
+
+ AnimationNodeStateMachinePlayback();
+};
+
+class AnimationNodeStateMachine : public AnimationRootNode {
+
+ GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
+
+private:
+ friend class AnimationNodeStateMachinePlayback;
+
+ struct State {
+ Ref<AnimationRootNode> node;
+ Vector2 position;
+ };
+
+ Map<StringName, State> states;
+
+ struct Transition {
+
+ StringName from;
+ StringName to;
+ Ref<AnimationNodeStateMachineTransition> transition;
+ };
+
+ Vector<Transition> transitions;
+
+ StringName playback;
+
+ StringName start_node;
+ StringName end_node;
+
+ Vector2 graph_offset;
+
+ void _tree_changed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -94,7 +143,10 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const;
public:
- void add_node(const StringName &p_name, Ref<AnimationNode> p_node);
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
Ref<AnimationNode> get_node(const StringName &p_name) const;
void remove_node(const StringName &p_name);
void rename_node(const StringName &p_name, const StringName &p_new_name);
@@ -102,6 +154,11 @@ public:
StringName get_node_name(const Ref<AnimationNode> &p_node) const;
void get_node_list(List<StringName> *r_nodes) const;
+ void set_node_position(const StringName &p_name, const Vector2 &p_position);
+ Vector2 get_node_position(const StringName &p_name) const;
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
+
bool has_transition(const StringName &p_from, const StringName &p_to) const;
int find_transition(const StringName &p_from, const StringName &p_to) const;
void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition);
@@ -124,17 +181,7 @@ public:
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;
- bool travel(const StringName &p_state);
- void start(const StringName &p_state);
- void stop();
- bool is_playing() const;
- StringName get_current_node() const;
- StringName get_blend_from_node() const;
- Vector<StringName> get_travel_path() const;
- float get_current_play_pos() const;
- float get_current_length() const;
-
- virtual void set_tree(AnimationTree *p_player);
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeStateMachine();
};
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index a660665d3f..d8db1973d2 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -960,8 +960,6 @@ Error AnimationPlayer::add_animation(const StringName &p_name, const Ref<Animati
ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER);
- //print_line("Add anim: "+String(p_name)+" name: "+p_animation->get_name());
-
if (animation_set.has(p_name)) {
_unref_anim(animation_set[p_name].animation);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 8bbc05eed3..76f0ee9359 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -5,6 +5,34 @@
#include "scene/scene_string_names.h"
#include "servers/audio/audio_stream.h"
+void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
+}
+
+Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
+ return Variant();
+}
+
+void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND(!state);
+ ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
+ ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
+ StringName path = state->tree->property_parent_map[base_path][p_name];
+
+ state->tree->property_map[path] = p_value;
+}
+
+Variant AnimationNode::get_parameter(const StringName &p_name) const {
+ ERR_FAIL_COND_V(!state, Variant());
+ ERR_FAIL_COND_V(!state->tree->property_parent_map.has(base_path), Variant());
+ ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name), Variant());
+
+ StringName path = state->tree->property_parent_map[base_path][p_name];
+ return state->tree->property_map[path];
+}
+
+void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
+}
+
void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) {
ERR_FAIL_COND(!state);
@@ -14,8 +42,8 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
if (animation.is_null()) {
- Ref<AnimationNodeBlendTree> btree = get_parent();
- if (btree.is_valid()) {
+ AnimationNodeBlendTree *btree = Object::cast_to<AnimationNodeBlendTree>(parent);
+ if (btree) {
String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this));
make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation));
} else {
@@ -37,10 +65,20 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time,
state->animation_states.push_back(anim_state);
}
-float AnimationNode::_pre_process(State *p_state, float p_time, bool p_seek) {
+float AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections) {
+
+ base_path = p_base_path;
+ parent = p_parent;
+ connections = p_connections;
state = p_state;
+
float t = process(p_time, p_seek);
+
state = NULL;
+ parent = NULL;
+ base_path = StringName();
+ connections.clear();
+
return t;
}
@@ -56,39 +94,39 @@ void AnimationNode::make_invalid(const String &p_reason) {
float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
ERR_FAIL_COND_V(!state, 0);
- ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs
- Ref<AnimationNodeBlendTree> tree = get_parent();
+ AnimationNodeBlendTree *blend_tree = Object::cast_to<AnimationNodeBlendTree>(parent);
+ ERR_FAIL_COND_V(!blend_tree, 0);
+
+ StringName node_name = connections[p_input];
- if (!tree.is_valid() && get_tree()->get_tree_root().ptr() != this) {
- make_invalid(RTR("Can't blend input because node is not in a tree"));
+ if (!blend_tree->has_node(node_name)) {
+ String name = blend_tree->get_node_name(Ref<AnimationNode>(this));
+ make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
return 0;
}
- ERR_FAIL_COND_V(!tree.is_valid(), 0); //should not happen
-
- StringName anim_name = inputs[p_input].connected_to;
+ Ref<AnimationNode> node = blend_tree->get_node(node_name);
- Ref<AnimationNode> node = tree->get_node(anim_name);
+ //inputs.write[p_input].last_pass = state->last_pass;
+ float activity=0;
+ float ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), NULL, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity);
- if (node.is_null()) {
+ Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
- String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
- make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
- return 0;
+ if (activity_ptr && p_input<activity_ptr->size()) {
+ activity_ptr->write[p_input].last_pass = state->last_pass;
+ activity_ptr->write[p_input].activity = activity;
}
-
- inputs.write[p_input].last_pass = state->last_pass;
-
- return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs.write[p_input].activity);
+ return ret;
}
-float AnimationNode::blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
+float AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) {
- return _blend_node(p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
+ return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_blend, p_filter, p_optimize);
}
-float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
+float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) {
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
ERR_FAIL_COND_V(!state, 0);
@@ -189,7 +227,19 @@ float AnimationNode::_blend_node(Ref<AnimationNode> p_node, float p_time, bool p
if (!p_seek && p_optimize && !any_valid) //pointless to go on, all are zero
return 0;
- return p_node->_pre_process(state, p_time, p_seek);
+ String new_path;
+ AnimationNode *new_parent;
+
+ //this is the slowest part of processing, but as strings process in powers of 2, and the paths always exist, it will not result in that many allocations
+ if (p_new_parent) {
+ new_parent = p_new_parent;
+ new_path = String(base_path) + String(p_subpath) + "/";
+ } else {
+ ERR_FAIL_COND_V(!parent, 0);
+ new_parent = parent;
+ new_path = String(parent->base_path) + String(p_subpath) + "/";
+ }
+ return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_connections);
}
int AnimationNode::get_input_count() const {
@@ -201,29 +251,6 @@ String AnimationNode::get_input_name(int p_input) {
return inputs[p_input].name;
}
-float AnimationNode::get_input_activity(int p_input) const {
-
- ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
- if (!get_tree())
- return 0;
-
- if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) {
- return 0;
- }
- return inputs[p_input].activity;
-}
-StringName AnimationNode::get_input_connection(int p_input) {
-
- ERR_FAIL_INDEX_V(p_input, inputs.size(), StringName());
- return inputs[p_input].connected_to;
-}
-
-void AnimationNode::set_input_connection(int p_input, const StringName &p_connection) {
-
- ERR_FAIL_INDEX(p_input, inputs.size());
- inputs.write[p_input].connected_to = p_connection;
-}
-
String AnimationNode::get_caption() const {
if (get_script_instance()) {
@@ -239,8 +266,6 @@ void AnimationNode::add_input(const String &p_name) {
Input input;
ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1);
input.name = p_name;
- input.activity = 0;
- input.last_pass = 0;
inputs.push_back(input);
emit_changed();
}
@@ -258,35 +283,6 @@ void AnimationNode::remove_input(int p_index) {
emit_changed();
}
-void AnimationNode::_set_parent(Object *p_parent) {
- set_parent(Object::cast_to<AnimationNode>(p_parent));
-}
-
-void AnimationNode::set_parent(AnimationNode *p_parent) {
- parent = p_parent; //do not use ref because parent contains children
- if (get_script_instance()) {
- get_script_instance()->call("_parent_set", p_parent);
- }
-}
-
-Ref<AnimationNode> AnimationNode::get_parent() const {
- if (parent) {
- return Ref<AnimationNode>(parent);
- }
-
- return Ref<AnimationNode>();
-}
-
-AnimationTree *AnimationNode::get_tree() const {
-
- return player;
-}
-
-AnimationPlayer *AnimationNode::get_player() const {
- ERR_FAIL_COND_V(!state, NULL);
- return state->player;
-}
-
float AnimationNode::process(float p_time, bool p_seek) {
if (get_script_instance()) {
@@ -320,22 +316,6 @@ bool AnimationNode::has_filter() const {
return false;
}
-void AnimationNode::set_position(const Vector2 &p_position) {
- position = p_position;
-}
-
-Vector2 AnimationNode::get_position() const {
- return position;
-}
-
-void AnimationNode::set_tree(AnimationTree *p_player) {
-
- if (player != NULL && p_player == NULL) {
- emit_signal("removed_from_graph");
- }
- player = p_player;
-}
-
Array AnimationNode::_get_filters() const {
Array paths;
@@ -361,12 +341,14 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
}
}
+Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
+ return Ref<AnimationNode>();
+}
+
void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
- ClassDB::bind_method(D_METHOD("get_input_connection", "input"), &AnimationNode::get_input_connection);
- ClassDB::bind_method(D_METHOD("get_input_activity", "input"), &AnimationNode::get_input_activity);
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
@@ -377,19 +359,15 @@ void AnimationNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_filter_enabled", "enable"), &AnimationNode::set_filter_enabled);
ClassDB::bind_method(D_METHOD("is_filter_enabled"), &AnimationNode::is_filter_enabled);
- ClassDB::bind_method(D_METHOD("set_position", "position"), &AnimationNode::set_position);
- ClassDB::bind_method(D_METHOD("get_position"), &AnimationNode::get_position);
-
ClassDB::bind_method(D_METHOD("_set_filters", "filters"), &AnimationNode::_set_filters);
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "blend"), &AnimationNode::blend_animation);
- ClassDB::bind_method(D_METHOD("blend_node", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "blend", "filter", "optimize"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("set_parent", "parent"), &AnimationNode::_set_parent);
- ClassDB::bind_method(D_METHOD("get_parent"), &AnimationNode::get_parent);
- ClassDB::bind_method(D_METHOD("get_tree"), &AnimationNode::get_tree);
+ ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
+ ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
@@ -397,9 +375,11 @@ void AnimationNode::_bind_methods() {
BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek")));
BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter"));
- BIND_VMETHOD(MethodInfo("_parent_set", PropertyInfo(Variant::OBJECT, "parent")));
ADD_SIGNAL(MethodInfo("removed_from_graph"));
+
+ ADD_SIGNAL(MethodInfo("tree_changed"));
+
BIND_ENUM_CONSTANT(FILTER_IGNORE);
BIND_ENUM_CONSTANT(FILTER_PASS);
BIND_ENUM_CONSTANT(FILTER_STOP);
@@ -410,8 +390,6 @@ AnimationNode::AnimationNode() {
state = NULL;
parent = NULL;
- player = NULL;
- set_local_to_scene(true);
filter_enabled = false;
}
@@ -420,18 +398,17 @@ AnimationNode::AnimationNode() {
void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
if (root.is_valid()) {
- root->set_tree(NULL);
- }
- if (p_root.is_valid()) {
- ERR_EXPLAIN("root node already set to another player");
- ERR_FAIL_COND(p_root->player);
+ root->disconnect("tree_changed", this, "_tree_changed");
}
+
root = p_root;
if (root.is_valid()) {
- root->set_tree(this);
+ root->connect("tree_changed", this, "_tree_changed");
}
+ properties_dirty = true;
+
update_configuration_warning();
}
@@ -699,7 +676,10 @@ void AnimationTree::_clear_caches() {
void AnimationTree::_process_graph(float p_delta) {
+ _update_properties(); //if properties need updating, update them
+
//check all tracks, see if they need modification
+
root_motion_transform = Transform();
if (!root.is_valid()) {
@@ -741,6 +721,7 @@ void AnimationTree::_process_graph(float p_delta) {
state.valid = true;
state.player = player;
state.last_pass = process_pass;
+ state.tree = this;
// root source blends
@@ -757,11 +738,11 @@ void AnimationTree::_process_graph(float p_delta) {
if (started) {
//if started, seek
- root->_pre_process(&state, 0, true);
+ root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, 0, true, Vector<StringName>());
started = false;
}
- root->_pre_process(&state, p_delta, false);
+ root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, p_delta, false, Vector<StringName>());
}
if (!state.valid) {
@@ -1297,6 +1278,149 @@ Transform AnimationTree::get_root_motion_transform() const {
return root_motion_transform;
}
+void AnimationTree::_tree_changed() {
+ if (properties_dirty) {
+ return;
+ }
+
+ call_deferred("_update_properties");
+ properties_dirty = true;
+}
+
+void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node) {
+
+ if (!property_parent_map.has(p_base_path)) {
+ property_parent_map[p_base_path] = HashMap<StringName, StringName>();
+ }
+
+ if (node->get_input_count() && !input_activity_map.has(p_base_path)) {
+
+ Vector<Activity> activity;
+ for(int i=0;i<node->get_input_count();i++) {
+ Activity a;
+ a.last_pass=0;
+ activity.push_back(a);
+ }
+ input_activity_map[p_base_path] = activity;
+ input_activity_map_get[String(p_base_path).substr(0,String(p_base_path).length()-1)]=&input_activity_map[p_base_path];
+ }
+
+ List<PropertyInfo> plist;
+ node->get_parameter_list(&plist);
+ for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) {
+ PropertyInfo pinfo = E->get();
+
+ StringName key = pinfo.name;
+
+ if (!property_map.has(p_base_path + key)) {
+ property_map[p_base_path + key] = node->get_parameter_default_value(key);
+ }
+
+ property_parent_map[p_base_path][key] = p_base_path + key;
+
+ pinfo.name = p_base_path + key;
+ properties.push_back(pinfo);
+ }
+
+ List<AnimationNode::ChildNode> children;
+ node->get_child_nodes(&children);
+
+ for (List<AnimationNode::ChildNode>::Element *E = children.front(); E; E = E->next()) {
+ _update_properties_for_node(p_base_path + E->get().name + "/", E->get().node);
+ }
+}
+
+void AnimationTree::_update_properties() {
+ if (!properties_dirty) {
+ return;
+ }
+
+ properties.clear();
+ property_parent_map.clear();
+ input_activity_map.clear();
+ input_activity_map_get.clear();
+
+ if (root.is_valid()) {
+ _update_properties_for_node(SceneStringNames::get_singleton()->parameters_base_path, root);
+ }
+
+ properties_dirty = false;
+
+ _change_notify();
+}
+
+bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
+ if (properties_dirty) {
+ _update_properties();
+ }
+
+ if (property_map.has(p_name)) {
+ property_map[p_name] = p_value;
+#ifdef TOOLS_ENABLED
+ _change_notify(p_name.operator String().utf8().get_data());
+#endif
+ return true;
+ }
+
+ return false;
+}
+
+bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
+ if (properties_dirty) {
+ const_cast<AnimationTree *>(this)->_update_properties();
+ }
+
+ if (property_map.has(p_name)) {
+ r_ret = property_map[p_name];
+ return true;
+ }
+
+ return false;
+}
+void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
+ if (properties_dirty) {
+ const_cast<AnimationTree *>(this)->_update_properties();
+ }
+
+ for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ p_list->push_back(E->get());
+ }
+}
+
+void AnimationTree::rename_parameter(const String &p_base, const String &p_new_base) {
+
+ //rename values first
+ for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
+ if (E->get().name.begins_with(p_base)) {
+ String new_name = E->get().name.replace_first(p_base, p_new_base);
+ property_map[new_name] = property_map[E->get().name];
+ }
+ }
+
+ //update tree second
+ properties_dirty = true;
+ _update_properties();
+}
+
+float AnimationTree::get_connection_activity(const StringName& p_path,int p_connection) const {
+
+ if (!input_activity_map_get.has(p_path)) {
+ return 0;
+ }
+ const Vector<Activity> *activity = input_activity_map_get[p_path];
+
+ if (!activity || p_connection<0 || p_connection>=activity->size()) {
+ return 0;
+ }
+
+ if ((*activity)[p_connection].last_pass != process_pass) {
+ return 0;
+ }
+
+ return (*activity)[p_connection].activity;
+}
+
+
void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationTree::set_active);
ClassDB::bind_method(D_METHOD("is_active"), &AnimationTree::is_active);
@@ -1315,11 +1439,16 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform);
+ ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationTree::_tree_changed);
+ ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
+
+ ClassDB::bind_method(D_METHOD("rename_parameter", "old_name", "new_name"), &AnimationTree::rename_parameter);
+
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance);
ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode");
@@ -1338,10 +1467,8 @@ AnimationTree::AnimationTree() {
cache_valid = false;
setup_pass = 1;
started = true;
+ properties_dirty = true;
}
AnimationTree::~AnimationTree() {
- if (root.is_valid()) {
- root->player = NULL;
- }
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 87092a4a0e..70f3932f21 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -23,9 +23,6 @@ public:
struct Input {
String name;
- StringName connected_to;
- float activity;
- uint64_t last_pass;
};
Vector<Input> inputs;
@@ -51,30 +48,33 @@ public:
List<AnimationState> animation_states;
bool valid;
AnimationPlayer *player;
+ AnimationTree *tree;
String invalid_reasons;
uint64_t last_pass;
};
Vector<float> blends;
State *state;
- float _pre_process(State *p_state, float p_time, bool p_seek);
+
+ float _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections);
void _pre_update_animations(HashMap<NodePath, int> *track_map);
- Vector2 position;
+ //all this is temporary
+ StringName base_path;
+ Vector<StringName> connections;
AnimationNode *parent;
- AnimationTree *player;
-
- float _blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
HashMap<NodePath, bool> filter;
bool filter_enabled;
Array _get_filters() const;
void _set_filters(const Array &p_filters);
+ friend class AnimationNodeBlendTree;
+ float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL);
protected:
void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend);
- float blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
+ float blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
float blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true);
void make_invalid(const String &p_reason);
@@ -85,20 +85,24 @@ protected:
void _set_parent(Object *p_parent);
public:
- void set_parent(AnimationNode *p_parent);
- Ref<AnimationNode> get_parent() const;
- virtual void set_tree(AnimationTree *p_player);
- AnimationTree *get_tree() const;
- AnimationPlayer *get_player() const;
+ virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
+ virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+
+ void set_parameter(const StringName &p_name, const Variant &p_value);
+ Variant get_parameter(const StringName &p_name) const;
+
+ struct ChildNode {
+ StringName name;
+ Ref<AnimationNode> node;
+ };
+
+ virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
virtual float process(float p_time, bool p_seek);
virtual String get_caption() const;
int get_input_count() const;
String get_input_name(int p_input);
- StringName get_input_connection(int p_input);
- void set_input_connection(int p_input, const StringName &p_connection);
- float get_input_activity(int p_input) const;
void add_input(const String &p_name);
void set_input_name(int p_input, const String &p_name);
@@ -112,8 +116,7 @@ public:
virtual bool has_filter() const;
- void set_position(const Vector2 &p_position);
- Vector2 get_position() const;
+ virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNode();
};
@@ -245,7 +248,29 @@ private:
NodePath root_motion_track;
Transform root_motion_transform;
+ friend class AnimationNode;
+ bool properties_dirty;
+ void _tree_changed();
+ void _update_properties();
+ List<PropertyInfo> properties;
+ HashMap<StringName, HashMap<StringName, StringName> > property_parent_map;
+ HashMap<StringName, Variant> property_map;
+
+ struct Activity {
+ uint64_t last_pass;
+ float activity;
+ };
+
+ HashMap<StringName, Vector<Activity> > input_activity_map;
+ HashMap<StringName, Vector<Activity> *> input_activity_map_get;
+
+ void _update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node);
+
protected:
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+
void _notification(int p_what);
static void _bind_methods();
@@ -272,8 +297,11 @@ public:
Transform get_root_motion_transform() const;
+ float get_connection_activity(const StringName &p_path, int p_connection) const;
void advance(float p_time);
+ void rename_parameter(const String &p_base, const String &p_new_base);
+
uint64_t get_last_process_pass() const;
AnimationTree();
~AnimationTree();
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
index 4991cedfab..9b1cb1369a 100644
--- a/scene/animation/skeleton_ik.cpp
+++ b/scene/animation/skeleton_ik.cpp
@@ -34,6 +34,8 @@
#include "skeleton_ik.h"
+#ifndef _3D_DISABLED
+
FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) {
for (int i = childs.size() - 1; 0 <= i; --i) {
if (p_bone_id == childs[i].bone) {
@@ -549,3 +551,5 @@ void SkeletonIK::_solve_chain() {
return;
FabrikInverseKinematic::solve(task, interpolation, use_magnet, magnet_position);
}
+
+#endif // _3D_DISABLED
diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h
index 366c599c01..08fb00e798 100644
--- a/scene/animation/skeleton_ik.h
+++ b/scene/animation/skeleton_ik.h
@@ -31,6 +31,8 @@
#ifndef SKELETON_IK_H
#define SKELETON_IK_H
+#ifndef _3D_DISABLED
+
/**
* @author AndreaCatania
*/
@@ -209,4 +211,6 @@ private:
void _solve_chain();
};
+#endif // _3D_DISABLED
+
#endif // SKELETON_IK_H
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp
index 863b278b62..7a9f2bd8d0 100644
--- a/scene/audio/audio_player.cpp
+++ b/scene/audio/audio_player.cpp
@@ -192,6 +192,7 @@ float AudioStreamPlayer::get_volume_db() const {
}
void AudioStreamPlayer::set_pitch_scale(float p_pitch_scale) {
+ ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
}
float AudioStreamPlayer::get_pitch_scale() const {
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index acdbd9de08..d17ae1d84c 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -31,7 +31,6 @@
#include "base_button.h"
#include "os/keyboard.h"
-#include "print_string.h"
#include "scene/main/viewport.h"
#include "scene/scene_string_names.h"
@@ -361,7 +360,6 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
return DRAW_DISABLED;
};
- //print_line("press attempt: "+itos(status.press_attempt)+" hover: "+itos(status.hovering)+" pressed: "+itos(status.pressed));
if (status.press_attempt == false && status.hovering && !status.pressed) {
return DRAW_HOVER;
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 03b25a138f..a34f2f1ad5 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "button.h"
-#include "print_string.h"
#include "servers/visual_server.h"
#include "translation.h"
@@ -76,8 +75,6 @@ void Button::_notification(int p_what) {
Color color;
Color color_icon(1, 1, 1, 1);
- //print_line(get_text()+": "+itos(is_flat())+" hover "+itos(get_draw_mode()));
-
Ref<StyleBox> style = get_stylebox("normal");
switch (get_draw_mode()) {
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 18f06eca31..e094a063be 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -357,7 +357,7 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
if (data.shader_override.has(E->get()))
hint |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED;
- p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_shaders/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph", hint));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "custom_shaders/" + E->get(), PROPERTY_HINT_RESOURCE_TYPE, "Shader,VisualShader", hint));
}
}
{
@@ -769,6 +769,7 @@ void Control::force_drag(const Variant &p_data, Control *p_control) {
void Control::set_drag_preview(Control *p_control) {
ERR_FAIL_COND(!is_inside_tree());
+ ERR_FAIL_COND(get_viewport()->gui_is_dragging());
get_viewport()->_gui_set_drag_preview(this, p_control);
}
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 25cb74a494..635f812805 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -582,7 +582,8 @@ void FileDialog::set_current_file(const String &p_file) {
int lp = p_file.find_last(".");
if (lp != -1) {
file->select(0, lp);
- file->grab_focus();
+ if (file->is_inside_tree())
+ file->grab_focus();
}
}
void FileDialog::set_current_path(const String &p_path) {
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 749efe8364..e82c0c4ad1 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -147,7 +147,6 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
grabbed = _get_point_from_pos(x);
//grab or select
if (grabbed != -1) {
- grabbed = false;
return;
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index d95ec9e495..a7163adbe6 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -356,14 +356,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (create_hot_zone(pos).has_point(p_point))
+ if (is_in_hot_zone(pos, p_point))
return true;
}
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (create_hot_zone(pos).has_point(p_point)) {
+ if (is_in_hot_zone(pos, p_point)) {
return true;
}
}
@@ -388,7 +388,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (create_hot_zone(pos).has_point(mpos)) {
+ if (is_in_hot_zone(pos, mpos)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
@@ -435,7 +435,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (create_hot_zone(pos).has_point(mpos)) {
+ if (is_in_hot_zone(pos, mpos)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
@@ -502,7 +502,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
int type = gn->get_connection_output_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
@@ -517,7 +517,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -557,8 +557,55 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
-Rect2 GraphEdit::create_hot_zone(const Vector2 &pos) {
- return Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2);
+bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) {
+
+ if (p_control->is_set_as_toplevel() || !p_control->is_visible())
+ return false;
+
+ if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) {
+ //test children
+ for (int i = 0; i < p_control->get_child_count(); i++) {
+ Control *subchild = Object::cast_to<Control>(p_control->get_child(i));
+ if (!subchild)
+ continue;
+ if (_check_clickable_control(subchild, pos - subchild->get_position())) {
+ return true;
+ }
+ }
+
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) {
+ if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos))
+ return false;
+
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *child = Object::cast_to<Control>(get_child(i));
+ if (!child)
+ continue;
+ Rect2 rect = child->get_rect();
+ if (rect.has_point(p_mouse_pos)) {
+
+ //check sub-controls
+ Vector2 subpos = p_mouse_pos - rect.position;
+
+ for (int j = 0; j < child->get_child_count(); j++) {
+ Control *subchild = Object::cast_to<Control>(child->get_child(j));
+ if (!subchild)
+ continue;
+
+ if (_check_clickable_control(subchild, subpos - subchild->get_position())) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
}
template <class Vector2>
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 64ba18681e..31a449eb59 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -131,7 +131,7 @@ private:
GraphEditFilter *top_layer;
void _top_layer_input(const Ref<InputEvent> &p_ev);
- Rect2 create_hot_zone(const Vector2 &pos);
+ bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos);
void _top_layer_draw();
void _connections_layer_draw();
@@ -172,6 +172,8 @@ private:
void _snap_toggled();
void _snap_value_changed(double);
+ bool _check_clickable_control(Control *p_control, const Vector2 &pos);
+
protected:
static void _bind_methods();
virtual void add_child_notify(Node *p_child);
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 5c79741682..d61bd97c2a 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -1423,6 +1423,9 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_custom_bg_color", "idx", "custom_bg_color"), &ItemList::set_item_custom_bg_color);
ClassDB::bind_method(D_METHOD("get_item_custom_bg_color", "idx"), &ItemList::get_item_custom_bg_color);
+ ClassDB::bind_method(D_METHOD("set_item_custom_fg_color", "idx", "custom_fg_color"), &ItemList::set_item_custom_fg_color);
+ ClassDB::bind_method(D_METHOD("get_item_custom_fg_color", "idx"), &ItemList::get_item_custom_fg_color);
+
ClassDB::bind_method(D_METHOD("set_item_tooltip_enabled", "idx", "enable"), &ItemList::set_item_tooltip_enabled);
ClassDB::bind_method(D_METHOD("is_item_tooltip_enabled", "idx"), &ItemList::is_item_tooltip_enabled);
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index d862e8669c..8560efdde5 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -68,8 +68,6 @@ void LinkButton::_notification(int p_what) {
Color color;
bool do_underline = false;
- //print_line(get_text()+": "+itos(is_flat())+" hover "+itos(get_draw_mode()));
-
switch (get_draw_mode()) {
case DRAW_NORMAL: {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index a3748bf14c..a5f9bea1b1 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -2034,7 +2034,6 @@ void RichTextLabel::selection_copy() {
if (text != "") {
OS::get_singleton()->set_clipboard(text);
- //print_line("COPY: "+text);
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 9a8dc62e4e..9616caa811 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -5692,15 +5692,12 @@ void TextEdit::_update_completion_candidates() {
bool pre_keyword = false;
bool cancel = false;
- //print_line("inquote: "+itos(inquote)+"first quote "+itos(first_quote)+" cofs-1 "+itos(cofs-1));
if (!inquote && first_quote == cofs - 1) {
//no completion here
- //print_line("cancel!");
cancel = true;
} else if (inquote && first_quote != -1) {
s = l.substr(first_quote, cofs - first_quote);
- //print_line("s: 1"+s);
} else if (cofs > 0 && l[cofs - 1] == ' ') {
int kofs = cofs - 1;
String kw;
@@ -5713,7 +5710,6 @@ void TextEdit::_update_completion_candidates() {
}
pre_keyword = keywords.has(kw);
- //print_line("KW "+kw+"? "+itos(pre_keyword));
} else {
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index d6a80bfb1a..e30f58e012 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -240,7 +240,7 @@ void Node::_propagate_enter_tree() {
void Node::_propagate_exit_tree() {
-//block while removing children
+ //block while removing children
#ifdef DEBUG_ENABLED
@@ -2082,9 +2082,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
} else {
Object *obj = ClassDB::instance(get_class());
- if (!obj) {
- print_line("could not duplicate: " + String(get_class()));
- }
+ ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class()));
ERR_FAIL_COND(!obj);
node = Object::cast_to<Node>(obj);
if (!node)
@@ -2179,9 +2177,7 @@ Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const {
Node *node = NULL;
Object *obj = ClassDB::instance(get_class());
- if (!obj) {
- print_line("could not duplicate: " + String(get_class()));
- }
+ ERR_EXPLAIN("Node: Could not duplicate: " + String(get_class()));
ERR_FAIL_COND_V(!obj, NULL);
node = Object::cast_to<Node>(obj);
if (!node)
@@ -2472,7 +2468,7 @@ static void _Node_debug_sn(Object *p_obj) {
path = n->get_name();
else
path = String(p->get_name()) + "/" + p->get_path_to(n);
- print_line(itos(p_obj->get_instance_id()) + "- Stray Node: " + path + " (Type: " + n->get_class() + ")");
+ print_line(itos(p_obj->get_instance_id()) + " - Stray Node: " + path + " (Type: " + n->get_class() + ")");
}
void Node::_print_stray_nodes() {
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index e99f785848..1d23650a1e 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1195,8 +1195,6 @@ void SceneTree::_update_root_rect() {
VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0);
}
- //print_line("VP SIZE: "+viewport_size+" OFFSET: "+offset+" = "+(offset*2+viewport_size));
- //print_line("SS: "+video_mode);
switch (stretch_mode) {
case STRETCH_MODE_2D: {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index e43c2da02d..d1b3eb9d9a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -185,6 +185,7 @@ public:
Viewport::GUI::GUI() {
+ dragging = false;
mouse_focus = NULL;
mouse_click_grabber = NULL;
mouse_focus_button = -1;
@@ -444,7 +445,7 @@ void Viewport::_notification(int p_what) {
Vector2 point = get_canvas_transform().affine_inverse().xform(pos);
Physics2DDirectSpaceState::ShapeResult res[64];
- int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true);
+ int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
for (int i = 0; i < rc; i++) {
if (res[i].collider_id && res[i].collider) {
@@ -527,7 +528,7 @@ void Viewport::_notification(int p_what) {
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
- bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true);
+ bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider = 0;
if (col) {
@@ -563,7 +564,7 @@ void Viewport::_notification(int p_what) {
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
- bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true);
+ bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
ObjectID new_collider = 0;
if (col) {
CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
@@ -1506,12 +1507,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
if (Object::cast_to<Viewport>(p_node))
return NULL;
- Control *c = Object::cast_to<Control>(p_node);
-
- if (c) {
- //print_line("at "+String(c->get_path())+" POS "+c->get_position()+" bt "+p_xform);
- }
-
//subwindows first!!
if (!p_node->is_visible()) {
@@ -1524,6 +1519,8 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
if (matrix.basis_determinant() == 0.0f)
return NULL;
+ Control *c = Object::cast_to<Control>(p_node);
+
if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
@@ -1654,7 +1651,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
*/
gui.mouse_focus = _gui_find_control(pos);
- //print_line("has mf "+itos(gui.mouse_focus!=NULL));
gui.mouse_focus_button = mb->get_button_index();
if (!gui.mouse_focus) {
@@ -1683,11 +1679,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
arr.push_back(gui.mouse_focus->get_class());
ScriptDebugger::get_singleton()->send_message("click_ctrl", arr);
}
-
-/*if (bool(GLOBAL_DEF("debug/print_clicked_control",false))) {
-
- print_line(String(gui.mouse_focus->get_path())+" - "+pos);
- }*/
#endif
if (mb->get_button_index() == BUTTON_LEFT) { //assign focus
@@ -1728,6 +1719,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
gui.drag_data = Variant();
+ gui.dragging = false;
if (gui.drag_preview) {
memdelete(gui.drag_preview);
@@ -1757,6 +1749,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
gui.drag_data = Variant();
+ gui.dragging = false;
_propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
//change mouse accordingly
}
@@ -1819,10 +1812,13 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *control = Object::cast_to<Control>(ci);
if (control) {
+ gui.dragging = true;
gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum);
if (gui.drag_data.get_type() != Variant::NIL) {
gui.mouse_focus = NULL;
+ } else {
+ gui.dragging = false;
}
if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
@@ -2262,6 +2258,7 @@ void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *
ERR_EXPLAIN("Drag data must be a value");
ERR_FAIL_COND(p_data.get_type() == Variant::NIL);
+ gui.dragging = true;
gui.drag_data = p_data;
gui.mouse_focus = NULL;
@@ -2701,6 +2698,9 @@ bool Viewport::is_snap_controls_to_pixels_enabled() const {
return snap_controls_to_pixels;
}
+bool Viewport::gui_is_dragging() const {
+ return gui.dragging;
+}
void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr);
@@ -2787,6 +2787,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
+ ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index e4ef373c77..450f235b79 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -274,6 +274,7 @@ private:
bool roots_order_dirty;
List<Control *> roots;
int canvas_sort_index; //for sorting items with canvas as root
+ bool dragging;
GUI();
} gui;
@@ -474,6 +475,8 @@ public:
void _subwindow_visibility_changed();
+ bool gui_is_dragging() const;
+
Viewport();
~Viewport();
};
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 382bddfb4e..3d837d4468 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -51,7 +51,6 @@
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
#include "scene/2d/particles_2d.h"
-
#include "scene/2d/path_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/2d/polygon_2d.h"
@@ -151,7 +150,6 @@
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/scene_format_text.h"
#include "scene/resources/segment_shape_2d.h"
-#include "scene/resources/shader_graph.h"
#include "scene/resources/shape_line_2d.h"
#include "scene/resources/sky_box.h"
#include "scene/resources/sphere_shape.h"
@@ -201,6 +199,7 @@
#include "scene/3d/room_instance.h"
#include "scene/3d/skeleton.h"
#include "scene/3d/soft_body.h"
+#include "scene/3d/spring_arm.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body.h"
#include "scene/3d/visibility_notifier.h"
@@ -366,17 +365,16 @@ void register_scene_types() {
ClassDB::register_class<Spatial>();
ClassDB::register_virtual_class<SpatialGizmo>();
ClassDB::register_class<Skeleton>();
- ClassDB::register_class<SkeletonIK>();
ClassDB::register_class<AnimationPlayer>();
ClassDB::register_class<Tween>();
OS::get_singleton()->yield(); //may take time to init
#ifndef _3D_DISABLED
- ClassDB::register_class<BoneAttachment>();
ClassDB::register_virtual_class<VisualInstance>();
ClassDB::register_virtual_class<GeometryInstance>();
ClassDB::register_class<Camera>();
+ ClassDB::register_class<ClippedCamera>();
ClassDB::register_class<Listener>();
ClassDB::register_class<ARVRCamera>();
ClassDB::register_class<ARVRController>();
@@ -415,6 +413,8 @@ void register_scene_types() {
ClassDB::register_class<AnimationNodeBlendSpace1D>();
ClassDB::register_class<AnimationNodeBlendSpace2D>();
ClassDB::register_class<AnimationNodeStateMachine>();
+ ClassDB::register_class<AnimationNodeStateMachinePlayback>();
+
ClassDB::register_class<AnimationNodeStateMachineTransition>();
ClassDB::register_class<AnimationNodeOutput>();
ClassDB::register_class<AnimationNodeOneShot>();
@@ -435,9 +435,14 @@ void register_scene_types() {
ClassDB::register_class<RigidBody>();
ClassDB::register_class<KinematicCollision>();
ClassDB::register_class<KinematicBody>();
+ ClassDB::register_class<SpringArm>();
+
ClassDB::register_class<PhysicalBone>();
ClassDB::register_class<SoftBody>();
+ ClassDB::register_class<SkeletonIK>();
+ ClassDB::register_class<BoneAttachment>();
+
ClassDB::register_class<VehicleBody>();
ClassDB::register_class<VehicleWheel>();
ClassDB::register_class<Area>();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 7041b62487..58e6db3f5e 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2906,8 +2906,6 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
//able to optimize more
erase = false;
} else {
-
- //print_line(itos(i)+"because of interp");
}
}
}
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index 39206ed043..5694099754 100644
--- a/scene/resources/bit_mask.cpp
+++ b/scene/resources/bit_mask.cpp
@@ -492,18 +492,14 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_
}
} while (reenter || popped);
-#ifdef DEBUG_ENABLED
- print_line("max stack size: " + itos(stack.size()));
-#endif
+ print_verbose("BitMap: Max stack size: " + itos(stack.size()));
}
Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+ print_verbose("BitMap: Rect: " + r);
-#ifdef DEBUG_ENABLED
- print_line("Rect: " + r);
-#endif
Point2i from;
Ref<BitMap> fill;
fill.instance();
@@ -515,13 +511,9 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl
if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
-#ifdef DEBUG_ENABLED
- print_line("pre reduce: " + itos(polygon.size()));
-#endif
+ print_verbose("BitMap: Pre reduce: " + itos(polygon.size()));
polygon = reduce(polygon, r, p_epsilon);
-#ifdef DEBUG_ENABLED
- print_line("post reduce: " + itos(polygon.size()));
-#endif
+ print_verbose("BitMap: Post reduce: " + itos(polygon.size()));
polygons.push_back(polygon);
fill_bits(this, fill, Point2i(j, i), r);
}
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 2f2abd4e08..c536f9c1d2 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -435,8 +435,6 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp
break;
}
- //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y));
-
if (ret.index == -1) {
//could not find texture to fit, create one
ret.x = 0;
diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp
index 29f1106d16..be394e19c4 100644
--- a/scene/resources/dynamic_font_stb.cpp
+++ b/scene/resources/dynamic_font_stb.cpp
@@ -214,7 +214,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
int advance;
stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0);
- //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale));
Character ch;
ch.texture_idx = -1;
ch.advance = advance * scale;
@@ -279,8 +278,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
break;
}
- //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y));
-
if (tex_index == -1) {
//could not find texture to fit, create one
tex_x = 0;
@@ -364,8 +361,6 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
chr.rect = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h);
- //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs));
-
char_map[p_char] = chr;
stbtt_FreeBitmap(cpbitmap, NULL);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 875b72159a..b6d1916b2c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -34,6 +34,8 @@
void Material::set_next_pass(const Ref<Material> &p_pass) {
+ ERR_FAIL_COND(p_pass == this);
+
if (next_pass == p_pass)
return;
@@ -398,8 +400,10 @@ void SpatialMaterial::_update_shader() {
if (flags[FLAG_USE_VERTEX_LIGHTING]) {
code += ",vertex_lighting";
}
+ bool using_world = false;
if (flags[FLAG_TRIPLANAR_USE_WORLD] && (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR])) {
code += ",world_vertex_coords";
+ using_world = true;
}
if (flags[FLAG_DONT_RECEIVE_SHADOWS]) {
code += ",shadows_disabled";
@@ -423,7 +427,7 @@ void SpatialMaterial::_update_shader() {
if (proximity_fade_enabled) {
code += "uniform float proximity_fade_distance;\n";
}
- if (distance_fade_enabled) {
+ if (distance_fade != DISTANCE_FADE_DISABLED) {
code += "uniform float distance_fade_min;\n";
code += "uniform float distance_fade_max;\n";
}
@@ -782,7 +786,7 @@ void SpatialMaterial::_update_shader() {
code += "\tALBEDO *= 1.0 - ref_amount;\n";
code += "\tALPHA = 1.0;\n";
- } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || distance_fade_enabled || proximity_fade_enabled) {
+ } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) {
code += "\tALPHA = albedo.a * albedo_tex.a;\n";
}
@@ -793,8 +797,47 @@ void SpatialMaterial::_update_shader() {
code += "\tALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n";
}
- if (distance_fade_enabled) {
- code += "\tALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n";
+ if (distance_fade != DISTANCE_FADE_DISABLED) {
+ if (distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER) {
+
+ code += "\t{\n";
+ if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
+ code += "\t\tfloat fade_distance = abs((INV_CAMERA_MATRIX * WORLD_MATRIX[3]).z);\n";
+
+ } else {
+ code += "\t\tfloat fade_distance=-VERTEX.z;\n";
+ }
+
+ code += "\t\tfloat fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n";
+ code += "\t\tint x = int(FRAGCOORD.x) % 4;\n";
+ code += "\t\tint y = int(FRAGCOORD.y) % 4;\n";
+ code += "\t\tint index = x + y * 4;\n";
+ code += "\t\tfloat limit = 0.0;\n\n";
+ code += "\t\tif (x < 8) {\n";
+ code += "\t\t\tif (index == 0) limit = 0.0625;\n";
+ code += "\t\t\tif (index == 1) limit = 0.5625;\n";
+ code += "\t\t\tif (index == 2) limit = 0.1875;\n";
+ code += "\t\t\tif (index == 3) limit = 0.6875;\n";
+ code += "\t\t\tif (index == 4) limit = 0.8125;\n";
+ code += "\t\t\tif (index == 5) limit = 0.3125;\n";
+ code += "\t\t\tif (index == 6) limit = 0.9375;\n";
+ code += "\t\t\tif (index == 7) limit = 0.4375;\n";
+ code += "\t\t\tif (index == 8) limit = 0.25;\n";
+ code += "\t\t\tif (index == 9) limit = 0.75;\n";
+ code += "\t\t\tif (index == 10) limit = 0.125;\n";
+ code += "\t\t\tif (index == 11) limit = 0.625;\n";
+ code += "\t\t\tif (index == 12) limit = 1.0;\n";
+ code += "\t\t\tif (index == 13) limit = 0.5;\n";
+ code += "\t\t\tif (index == 14) limit = 0.875;\n";
+ code += "\t\t\tif (index == 15) limit = 0.375;\n";
+ code += "\t\t}\n\n";
+ code += "\tif (fade < limit)\n";
+ code += "\t\tdiscard;\n";
+ code += "\t}\n\n";
+
+ } else {
+ code += "\tALPHA*=clamp(smoothstep(distance_fade_min,distance_fade_max,-VERTEX.z),0.0,1.0);\n";
+ }
}
if (features[FEATURE_RIM]) {
@@ -1324,7 +1367,7 @@ void SpatialMaterial::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
- if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && !distance_fade_enabled) {
+ if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
property.usage = 0;
}
@@ -1645,15 +1688,15 @@ float SpatialMaterial::get_proximity_fade_distance() const {
return proximity_fade_distance;
}
-void SpatialMaterial::set_distance_fade(bool p_enable) {
+void SpatialMaterial::set_distance_fade(DistanceFadeMode p_mode) {
- distance_fade_enabled = p_enable;
+ distance_fade = p_mode;
_queue_shader_change();
_change_notify();
}
-bool SpatialMaterial::is_distance_fade_enabled() const {
+SpatialMaterial::DistanceFadeMode SpatialMaterial::get_distance_fade() const {
- return distance_fade_enabled;
+ return distance_fade;
}
void SpatialMaterial::set_distance_fade_max_distance(float p_distance) {
@@ -1859,8 +1902,8 @@ void SpatialMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &SpatialMaterial::set_proximity_fade_distance);
ClassDB::bind_method(D_METHOD("get_proximity_fade_distance"), &SpatialMaterial::get_proximity_fade_distance);
- ClassDB::bind_method(D_METHOD("set_distance_fade", "enabled"), &SpatialMaterial::set_distance_fade);
- ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &SpatialMaterial::is_distance_fade_enabled);
+ ClassDB::bind_method(D_METHOD("set_distance_fade", "mode"), &SpatialMaterial::set_distance_fade);
+ ClassDB::bind_method(D_METHOD("get_distance_fade"), &SpatialMaterial::get_distance_fade);
ClassDB::bind_method(D_METHOD("set_distance_fade_max_distance", "distance"), &SpatialMaterial::set_distance_fade_max_distance);
ClassDB::bind_method(D_METHOD("get_distance_fade_max_distance"), &SpatialMaterial::get_distance_fade_max_distance);
@@ -1892,7 +1935,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "params_depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never,Opaque Pre-Pass"), "set_depth_draw_mode", "get_depth_draw_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_line_width", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_line_width", "get_line_width");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "params_billboard_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particle Billboard1"), "set_billboard_mode", "get_billboard_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "params_billboard_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particle Billboard"), "set_billboard_mode", "get_billboard_mode");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_billboard_keep_scale"), "set_flag", "get_flag", FLAG_BILLBOARD_KEEP_SCALE);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "params_grow"), "set_grow_enabled", "is_grow_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_grow_amount", PROPERTY_HINT_RANGE, "-16,10,0.01"), "set_grow", "get_grow");
@@ -2003,7 +2046,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("Distance Fade", "distance_fade_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enable"), "set_distance_fade", "is_distance_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "distance_fade_mode", PROPERTY_HINT_ENUM, "Disabled,PixelAlpha,PixelDither,ObjectDither"), "set_distance_fade", "get_distance_fade");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_min_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_distance_fade_min_distance", "get_distance_fade_min_distance");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "distance_fade_max_distance", PROPERTY_HINT_RANGE, "0,4096,0.1"), "set_distance_fade_max_distance", "get_distance_fade_max_distance");
@@ -2101,6 +2144,11 @@ void SpatialMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_OP_ADD);
BIND_ENUM_CONSTANT(EMISSION_OP_MULTIPLY);
+
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_DISABLED);
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_ALPHA);
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_PIXEL_DITHER);
+ BIND_ENUM_CONSTANT(DISTANCE_FADE_OBJECT_DITHER);
}
SpatialMaterial::SpatialMaterial() :
@@ -2139,7 +2187,7 @@ SpatialMaterial::SpatialMaterial() :
emission_op = EMISSION_OP_ADD;
proximity_fade_enabled = false;
- distance_fade_enabled = false;
+ distance_fade = DISTANCE_FADE_DISABLED;
set_proximity_fade_distance(1);
set_distance_fade_min_distance(0);
set_distance_fade_max_distance(10);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 7a1a4acfbf..f43d240a53 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -233,6 +233,13 @@ public:
EMISSION_OP_MULTIPLY
};
+ enum DistanceFadeMode {
+ DISTANCE_FADE_DISABLED,
+ DISTANCE_FADE_PIXEL_ALPHA,
+ DISTANCE_FADE_PIXEL_DITHER,
+ DISTANCE_FADE_OBJECT_DITHER,
+ };
+
private:
union MaterialKey {
@@ -251,7 +258,7 @@ private:
uint64_t billboard_mode : 2;
uint64_t grow : 1;
uint64_t proximity_fade : 1;
- uint64_t distance_fade : 1;
+ uint64_t distance_fade : 2;
uint64_t emission_op : 1;
};
@@ -296,7 +303,7 @@ private:
mk.deep_parallax = deep_parallax ? 1 : 0;
mk.grow = grow_enabled;
mk.proximity_fade = proximity_fade_enabled;
- mk.distance_fade = distance_fade_enabled;
+ mk.distance_fade = distance_fade;
mk.emission_op = emission_op;
return mk;
@@ -402,7 +409,7 @@ private:
bool proximity_fade_enabled;
float proximity_fade_distance;
- bool distance_fade_enabled;
+ DistanceFadeMode distance_fade;
float distance_fade_max_distance;
float distance_fade_min_distance;
@@ -583,8 +590,8 @@ public:
void set_proximity_fade_distance(float p_distance);
float get_proximity_fade_distance() const;
- void set_distance_fade(bool p_enable);
- bool is_distance_fade_enabled() const;
+ void set_distance_fade(DistanceFadeMode p_mode);
+ DistanceFadeMode get_distance_fade() const;
void set_distance_fade_max_distance(float p_distance);
float get_distance_fade_max_distance() const;
@@ -630,6 +637,7 @@ VARIANT_ENUM_CAST(SpatialMaterial::SpecularMode)
VARIANT_ENUM_CAST(SpatialMaterial::BillboardMode)
VARIANT_ENUM_CAST(SpatialMaterial::TextureChannel)
VARIANT_ENUM_CAST(SpatialMaterial::EmissionOperator)
+VARIANT_ENUM_CAST(SpatialMaterial::DistanceFadeMode)
//////////////////////
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 4e6004709e..042cf28fec 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1241,7 +1241,7 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
surfaces_tools.push_back(st); //stay there
}
- print_line("gen indices: " + itos(gen_index_count));
+ print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
@@ -1334,7 +1334,7 @@ void ArrayMesh::_bind_methods() {
ClassDB::set_method_flags(get_class_static(), _scs_create("center_geometry"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ClassDB::bind_method(D_METHOD("regen_normalmaps"), &ArrayMesh::regen_normalmaps);
ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normalmaps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
- ClassDB::bind_method(D_METHOD("lightmap_unwrap"), &ArrayMesh::lightmap_unwrap);
+ ClassDB::bind_method(D_METHOD("lightmap_unwrap", "transform", "texel_size"), &ArrayMesh::lightmap_unwrap);
ClassDB::set_method_flags(get_class_static(), _scs_create("lightmap_unwrap"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ClassDB::bind_method(D_METHOD("get_faces"), &ArrayMesh::get_faces);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &ArrayMesh::generate_triangle_mesh);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 07783d5f4a..f034e07ff9 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -106,7 +106,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (i == 0 && base_scene_idx >= 0) {
//scene inheritance on root node
- //print_line("scene inherit");
Ref<PackedScene> sdata = props[base_scene_idx];
ERR_FAIL_COND_V(!sdata.is_valid(), NULL);
node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); //only main gets main edit state
@@ -117,7 +116,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
} else if (n.instance >= 0) {
//instance a scene into this node
- //print_line("instance");
if (n.instance & FLAG_INSTANCE_IS_PLACEHOLDER) {
String path = props[n.instance & FLAG_MASK];
@@ -141,7 +139,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
} else if (n.type == TYPE_INSTANCED) {
- //print_line("instanced");
//get the node from somewhere, it likely already exists from another instance
if (parent) {
node = parent->_get_child_by_name(snames[n.name]);
@@ -152,7 +149,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
#endif
}
} else if (ClassDB::is_class_enabled(snames[n.type])) {
- //print_line("created");
//node belongs to this scene and must be created
Object *obj = ClassDB::instance(snames[n.type]);
if (!Object::cast_to<Node>(obj)) {
@@ -491,15 +487,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
if (E->get().usage & PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE) {
isdefault = true; //is script default value
}
- /*
- if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) {
- continue;
- }
- */
-
- //print_line("PASSED!");
- //print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE));
- //print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one()));
if (pack_state_stack.size()) {
// we are on part of an instanced subscene
diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h
index dfe48d94cf..c69e44a7da 100644
--- a/scene/resources/physics_material.h
+++ b/scene/resources/physics_material.h
@@ -37,7 +37,7 @@ class PhysicsMaterial : public Resource {
GDCLASS(PhysicsMaterial, Resource);
OBJ_SAVE_TYPE(PhysicsMaterial);
- RES_BASE_EXTENSION("PhyMat");
+ RES_BASE_EXTENSION("phymat");
real_t friction;
bool rough;
diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp
deleted file mode 100644
index 070cc84863..0000000000
--- a/scene/resources/shader_graph.cpp
+++ /dev/null
@@ -1,2596 +0,0 @@
-/*************************************************************************/
-/* shader_graph.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 "shader_graph.h"
-
-#include "scene/scene_string_names.h"
-
-// FIXME: Needs to be ported to the new 3.0 shader API
-#if 0
-Array ShaderGraph::_get_node_list(ShaderType p_type) const {
-
- List<int> nodes;
- get_node_list(p_type,&nodes);
- Array arr(true);
- for (List<int>::Element *E=nodes.front();E;E=E->next())
- arr.push_back(E->get());
- return arr;
-}
-Array ShaderGraph::_get_connections(ShaderType p_type) const {
-
- List<Connection> connections;
- get_node_connections(p_type,&connections);
- Array arr(true);
- for (List<Connection>::Element *E=connections.front();E;E=E->next()) {
-
- Dictionary d(true);
- d["src_id"]=E->get().src_id;
- d["src_slot"]=E->get().src_slot;
- d["dst_id"]=E->get().dst_id;
- d["dst_slot"]=E->get().dst_slot;
- arr.push_back(d);
-
- }
- return arr;
-}
-
-void ShaderGraph::_set_data(const Dictionary &p_data) {
-
- Dictionary d=p_data;
- ERR_FAIL_COND(!d.has("shaders"));
- Array sh=d["shaders"];
- ERR_FAIL_COND(sh.size()!=3);
-
- for(int t=0;t<3;t++) {
- Array data=sh[t];
- ERR_FAIL_COND((data.size()%6)!=0);
- shader[t].node_map.clear();
- for(int i=0;i<data.size();i+=6) {
-
- Node n;
- n.id=data[i+0];
- n.type=NodeType(int(data[i+1]));
- n.pos=data[i+2];
- n.param1=data[i+3];
- n.param2=data[i+4];
-
- Array conns=data[i+5];
- ERR_FAIL_COND((conns.size()%3)!=0);
-
- for(int j=0;j<conns.size();j+=3) {
- SourceSlot ss;
- int ls=conns[j+0];
- if (ls == SLOT_DEFAULT_VALUE) {
- n.defaults[conns[j+1]]=conns[j+2];
- } else {
- ss.id=conns[j+1];
- ss.slot=conns[j+2];
- n.connections[ls]=ss;
- }
- }
- shader[t].node_map[n.id]=n;
-
- }
- }
-
- _pending_update_shader=true;
- _update_shader();
-
-}
-
-Dictionary ShaderGraph::_get_data() const {
-
- Array sh;
- for(int i=0;i<3;i++) {
- Array data;
- int ec = shader[i].node_map.size();
- data.resize(ec*6);
- int idx=0;
- for (Map<int,Node>::Element*E=shader[i].node_map.front();E;E=E->next()) {
-
- data[idx+0]=E->key();
- data[idx+1]=E->get().type;
- data[idx+2]=E->get().pos;
- data[idx+3]=E->get().param1;
- data[idx+4]=E->get().param2;
-
- Array conns;
- conns.resize(E->get().connections.size()*3+E->get().defaults.size()*3);
- int idx2=0;
- for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
-
- conns[idx2+0]=F->key();
- conns[idx2+1]=F->get().id;
- conns[idx2+2]=F->get().slot;
- idx2+=3;
- }
- for(Map<int,Variant>::Element*F=E->get().defaults.front();F;F=F->next()) {
-
- conns[idx2+0]=SLOT_DEFAULT_VALUE;
- conns[idx2+1]=F->key();
- conns[idx2+2]=F->get();
- idx2+=3;
- }
-
- data[idx+5]=conns;
- idx+=6;
- }
- sh.push_back(data);
- }
-
- Dictionary data;
- data["shaders"]=sh;
- return data;
-}
-
-
-
-ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
-
- ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK);
- return shader[p_type].error;
-}
-
-int ShaderGraph::node_count(ShaderType p_which, int p_type)
-{
- int count=0;
- for (Map<int,Node>::Element *E=shader[p_which].node_map.front();E;E=E->next())
- if (E->get().type==p_type)
- count++;
- return count;
-}
-
-void ShaderGraph::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("_update_shader"),&ShaderGraph::_update_shader);
-
- ClassDB::bind_method(D_METHOD("node_add","shader_type","node_type","id"),&ShaderGraph::node_add);
- ClassDB::bind_method(D_METHOD("node_remove","shader_type","id"),&ShaderGraph::node_remove);
- ClassDB::bind_method(D_METHOD("node_set_position","shader_type","id","position"),&ShaderGraph::node_set_position);
- ClassDB::bind_method(D_METHOD("node_get_position","shader_type","id"),&ShaderGraph::node_get_position);
-
- ClassDB::bind_method(D_METHOD("node_get_type","shader_type","id"),&ShaderGraph::node_get_type);
-
- ClassDB::bind_method(D_METHOD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
-
- ClassDB::bind_method(D_METHOD("default_set_value","shader_type","id","param_id","value"), &ShaderGraph::default_set_value);
- ClassDB::bind_method(D_METHOD("default_get_value","shader_type","id","param_id"), &ShaderGraph::default_get_value);
-
- ClassDB::bind_method(D_METHOD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
- ClassDB::bind_method(D_METHOD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_get_value);
-
- ClassDB::bind_method(D_METHOD("vec_const_node_set_value","shader_type","id","value"),&ShaderGraph::vec_const_node_set_value);
- ClassDB::bind_method(D_METHOD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_get_value);
-
- ClassDB::bind_method(D_METHOD("rgb_const_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_const_node_set_value);
- ClassDB::bind_method(D_METHOD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_get_value);
-
- ClassDB::bind_method(D_METHOD("xform_const_node_set_value","shader_type","id","value"),&ShaderGraph::xform_const_node_set_value);
- ClassDB::bind_method(D_METHOD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_get_value);
-
-
- //void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
-
- ClassDB::bind_method(D_METHOD("texture_node_set_filter_size","shader_type","id","filter_size"),&ShaderGraph::texture_node_set_filter_size);
- ClassDB::bind_method(D_METHOD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_get_filter_size);
-
- ClassDB::bind_method(D_METHOD("texture_node_set_filter_strength","shader_type","id","filter_strength"),&ShaderGraph::texture_node_set_filter_strength);
- ClassDB::bind_method(D_METHOD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_get_filter_strength);
-
- ClassDB::bind_method(D_METHOD("scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::scalar_op_node_set_op);
- ClassDB::bind_method(D_METHOD("scalar_op_node_get_op","shader_type","id"),&ShaderGraph::scalar_op_node_get_op);
-
- ClassDB::bind_method(D_METHOD("vec_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_op_node_set_op);
- ClassDB::bind_method(D_METHOD("vec_op_node_get_op","shader_type","id"),&ShaderGraph::vec_op_node_get_op);
-
- ClassDB::bind_method(D_METHOD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op);
- ClassDB::bind_method(D_METHOD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op);
-
- ClassDB::bind_method(D_METHOD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op);
- ClassDB::bind_method(D_METHOD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op);
-
-
- ClassDB::bind_method(D_METHOD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation);
- ClassDB::bind_method(D_METHOD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation);
-
- ClassDB::bind_method(D_METHOD("scalar_func_node_set_function","shader_type","id","func"),&ShaderGraph::scalar_func_node_set_function);
- ClassDB::bind_method(D_METHOD("scalar_func_node_get_function","shader_type","id"),&ShaderGraph::scalar_func_node_get_function);
-
- ClassDB::bind_method(D_METHOD("vec_func_node_set_function","shader_type","id","func"),&ShaderGraph::vec_func_node_set_function);
- ClassDB::bind_method(D_METHOD("vec_func_node_get_function","shader_type","id"),&ShaderGraph::vec_func_node_get_function);
-
- ClassDB::bind_method(D_METHOD("input_node_set_name","shader_type","id","name"),&ShaderGraph::input_node_set_name);
- ClassDB::bind_method(D_METHOD("input_node_get_name","shader_type","id"),&ShaderGraph::input_node_get_name);
-
- ClassDB::bind_method(D_METHOD("scalar_input_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_input_node_set_value);
- ClassDB::bind_method(D_METHOD("scalar_input_node_get_value","shader_type","id"),&ShaderGraph::scalar_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("vec_input_node_set_value","shader_type","id","value"),&ShaderGraph::vec_input_node_set_value);
- ClassDB::bind_method(D_METHOD("vec_input_node_get_value","shader_type","id"),&ShaderGraph::vec_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("rgb_input_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_input_node_set_value);
- ClassDB::bind_method(D_METHOD("rgb_input_node_get_value","shader_type","id"),&ShaderGraph::rgb_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("xform_input_node_set_value","shader_type","id","value"),&ShaderGraph::xform_input_node_set_value);
- ClassDB::bind_method(D_METHOD("xform_input_node_get_value","shader_type","id"),&ShaderGraph::xform_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("texture_input_node_set_value","shader_type","id","value"),&ShaderGraph::texture_input_node_set_value);
- ClassDB::bind_method(D_METHOD("texture_input_node_get_value","shader_type","id"),&ShaderGraph::texture_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("cubemap_input_node_set_value","shader_type","id","value"),&ShaderGraph::cubemap_input_node_set_value);
- ClassDB::bind_method(D_METHOD("cubemap_input_node_get_value","shader_type","id"),&ShaderGraph::cubemap_input_node_get_value);
-
- ClassDB::bind_method(D_METHOD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text);
- ClassDB::bind_method(D_METHOD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text);
-
- ClassDB::bind_method(D_METHOD("color_ramp_node_set_ramp","shader_type","id","colors","offsets"),&ShaderGraph::color_ramp_node_set_ramp);
- ClassDB::bind_method(D_METHOD("color_ramp_node_get_colors","shader_type","id"),&ShaderGraph::color_ramp_node_get_colors);
- ClassDB::bind_method(D_METHOD("color_ramp_node_get_offsets","shader_type","id"),&ShaderGraph::color_ramp_node_get_offsets);
-
- ClassDB::bind_method(D_METHOD("curve_map_node_set_points","shader_type","id","points"),&ShaderGraph::curve_map_node_set_points);
- ClassDB::bind_method(D_METHOD("curve_map_node_get_points","shader_type","id"),&ShaderGraph::curve_map_node_get_points);
-
- ClassDB::bind_method(D_METHOD("connect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node);
- ClassDB::bind_method(D_METHOD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected);
- ClassDB::bind_method(D_METHOD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node);
- ClassDB::bind_method(D_METHOD("get_node_connections","shader_type"),&ShaderGraph::_get_connections);
-
- ClassDB::bind_method(D_METHOD("clear","shader_type"),&ShaderGraph::clear);
-
- ClassDB::bind_method(D_METHOD("node_set_state","shader_type","id","state"),&ShaderGraph::node_set_state);
- ClassDB::bind_method(D_METHOD("node_get_state","shader_type","id"),&ShaderGraph::node_get_state);
-
- ClassDB::bind_method(D_METHOD("_set_data"),&ShaderGraph::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"),&ShaderGraph::_get_data);
-
- ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data","_get_data");
-
- //void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
-
-
- BIND_ENUM_CONSTANT( NODE_INPUT ); // all inputs (shader type dependent)
- BIND_ENUM_CONSTANT( NODE_SCALAR_CONST ); //scalar constant
- BIND_ENUM_CONSTANT( NODE_VEC_CONST ); //vec3 constant
- BIND_ENUM_CONSTANT( NODE_RGB_CONST ); //rgb constant (shows a color picker instead)
- BIND_ENUM_CONSTANT( NODE_XFORM_CONST ); // 4x4 matrix constant
- BIND_ENUM_CONSTANT( NODE_TIME ); // time in seconds
- BIND_ENUM_CONSTANT( NODE_SCREEN_TEX ); // screen texture sampler (takes UV) (only usable in fragment shader)
- BIND_ENUM_CONSTANT( NODE_SCALAR_OP ); // scalar vs scalar op (mul ); add ); div ); etc)
- BIND_ENUM_CONSTANT( NODE_VEC_OP ); // vec3 vs vec3 op (mul );ad );div );crossprod );etc)
- BIND_ENUM_CONSTANT( NODE_VEC_SCALAR_OP ); // vec3 vs scalar op (mul ); add ); div ); etc)
- BIND_ENUM_CONSTANT( NODE_RGB_OP ); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc.
- BIND_ENUM_CONSTANT( NODE_XFORM_MULT ); // mat4 x mat4
- BIND_ENUM_CONSTANT( NODE_XFORM_VEC_MULT ); // mat4 x vec3 mult (with no-translation option)
- BIND_ENUM_CONSTANT( NODE_XFORM_VEC_INV_MULT ); // mat4 x vec3 inverse mult (with no-translation option)
- BIND_ENUM_CONSTANT( NODE_SCALAR_FUNC ); // scalar function (sin ); cos ); etc)
- BIND_ENUM_CONSTANT( NODE_VEC_FUNC ); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc)
- BIND_ENUM_CONSTANT( NODE_VEC_LEN ); // vec3 length
- BIND_ENUM_CONSTANT( NODE_DOT_PROD ); // vec3 . vec3 (dot product -> scalar output)
- BIND_ENUM_CONSTANT( NODE_VEC_TO_SCALAR ); // 1 vec3 input ); 3 scalar outputs
- BIND_ENUM_CONSTANT( NODE_SCALAR_TO_VEC ); // 3 scalar input ); 1 vec3 output
- BIND_ENUM_CONSTANT( NODE_VEC_TO_XFORM ); // 3 vec input ); 1 xform output
- BIND_ENUM_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
- BIND_ENUM_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
- BIND_ENUM_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation (with optional curve)
- BIND_ENUM_CONSTANT( NODE_COLOR_RAMP );
- BIND_ENUM_CONSTANT( NODE_CURVE_MAP );
- BIND_ENUM_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material)
- BIND_ENUM_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material)
- BIND_ENUM_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material)
- BIND_ENUM_CONSTANT( NODE_DEFAULT_TEXTURE );
- BIND_ENUM_CONSTANT( NODE_OUTPUT ); // output (shader type dependent)
- BIND_ENUM_CONSTANT( NODE_COMMENT ); // comment
- BIND_ENUM_CONSTANT( NODE_TYPE_MAX );
-
- BIND_ENUM_CONSTANT( SLOT_TYPE_SCALAR );
- BIND_ENUM_CONSTANT( SLOT_TYPE_VEC );
- BIND_ENUM_CONSTANT( SLOT_TYPE_XFORM );
- BIND_ENUM_CONSTANT( SLOT_TYPE_TEXTURE );
- BIND_ENUM_CONSTANT( SLOT_MAX );
-
- BIND_ENUM_CONSTANT( SHADER_TYPE_VERTEX );
- BIND_ENUM_CONSTANT( SHADER_TYPE_FRAGMENT );
- BIND_ENUM_CONSTANT( SHADER_TYPE_LIGHT );
- BIND_ENUM_CONSTANT( SHADER_TYPE_MAX );
-
-
- BIND_ENUM_CONSTANT( SLOT_IN );
- BIND_ENUM_CONSTANT( SLOT_OUT );
-
- BIND_ENUM_CONSTANT( GRAPH_OK );
- BIND_ENUM_CONSTANT( GRAPH_ERROR_CYCLIC );
- BIND_ENUM_CONSTANT( GRAPH_ERROR_MISSING_CONNECTIONS );
-
- BIND_ENUM_CONSTANT( SCALAR_OP_ADD );
- BIND_ENUM_CONSTANT( SCALAR_OP_SUB );
- BIND_ENUM_CONSTANT( SCALAR_OP_MUL );
- BIND_ENUM_CONSTANT( SCALAR_OP_DIV );
- BIND_ENUM_CONSTANT( SCALAR_OP_MOD );
- BIND_ENUM_CONSTANT( SCALAR_OP_POW );
- BIND_ENUM_CONSTANT( SCALAR_OP_MAX );
- BIND_ENUM_CONSTANT( SCALAR_OP_MIN );
- BIND_ENUM_CONSTANT( SCALAR_OP_ATAN2 );
- BIND_ENUM_CONSTANT( SCALAR_MAX_OP );
-
- BIND_ENUM_CONSTANT( VEC_OP_ADD );
- BIND_ENUM_CONSTANT( VEC_OP_SUB );
- BIND_ENUM_CONSTANT( VEC_OP_MUL );
- BIND_ENUM_CONSTANT( VEC_OP_DIV );
- BIND_ENUM_CONSTANT( VEC_OP_MOD );
- BIND_ENUM_CONSTANT( VEC_OP_POW );
- BIND_ENUM_CONSTANT( VEC_OP_MAX );
- BIND_ENUM_CONSTANT( VEC_OP_MIN );
- BIND_ENUM_CONSTANT( VEC_OP_CROSS );
- BIND_ENUM_CONSTANT( VEC_MAX_OP );
-
- BIND_ENUM_CONSTANT( VEC_SCALAR_OP_MUL );
- BIND_ENUM_CONSTANT( VEC_SCALAR_OP_DIV );
- BIND_ENUM_CONSTANT( VEC_SCALAR_OP_POW );
- BIND_ENUM_CONSTANT( VEC_SCALAR_MAX_OP );
-
- BIND_ENUM_CONSTANT( RGB_OP_SCREEN );
- BIND_ENUM_CONSTANT( RGB_OP_DIFFERENCE );
- BIND_ENUM_CONSTANT( RGB_OP_DARKEN );
- BIND_ENUM_CONSTANT( RGB_OP_LIGHTEN );
- BIND_ENUM_CONSTANT( RGB_OP_OVERLAY );
- BIND_ENUM_CONSTANT( RGB_OP_DODGE );
- BIND_ENUM_CONSTANT( RGB_OP_BURN );
- BIND_ENUM_CONSTANT( RGB_OP_SOFT_LIGHT );
- BIND_ENUM_CONSTANT( RGB_OP_HARD_LIGHT );
- BIND_ENUM_CONSTANT( RGB_MAX_OP );
-
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SIN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_COS );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_TAN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ASIN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ACOS );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ATAN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SINH );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_COSH );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_TANH );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_LOG );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_EXP );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SQRT );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ABS );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SIGN );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_FLOOR );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_ROUND );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_CEIL );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_FRAC );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_SATURATE );
- BIND_ENUM_CONSTANT( SCALAR_FUNC_NEGATE );
- BIND_ENUM_CONSTANT( SCALAR_MAX_FUNC );
-
- BIND_ENUM_CONSTANT( VEC_FUNC_NORMALIZE );
- BIND_ENUM_CONSTANT( VEC_FUNC_SATURATE );
- BIND_ENUM_CONSTANT( VEC_FUNC_NEGATE );
- BIND_ENUM_CONSTANT( VEC_FUNC_RECIPROCAL );
- BIND_ENUM_CONSTANT( VEC_FUNC_RGB2HSV );
- BIND_ENUM_CONSTANT( VEC_FUNC_HSV2RGB );
- BIND_ENUM_CONSTANT( VEC_MAX_FUNC );
-
- ADD_SIGNAL(MethodInfo("updated"));
-}
-
-
-String ShaderGraph::_find_unique_name(const String& p_base) {
-
-
-
- int idx=1;
- while(true) {
- String tocmp=p_base;
- if (idx>1) {
- tocmp+="_"+itos(idx);
- }
- bool valid=true;
- for(int i=0;i<3;i++) {
- if (!valid)
- break;
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
- if (E->get().type!=NODE_SCALAR_INPUT && E->get().type!=NODE_VEC_INPUT && E->get().type==NODE_RGB_INPUT && E->get().type==NODE_XFORM_INPUT && E->get().type==NODE_TEXTURE_INPUT && E->get().type==NODE_CUBEMAP_INPUT)
- continue;
- String name = E->get().param1;
- if (name==tocmp) {
- valid=false;
- break;
- }
-
- }
- }
-
- if (!valid) {
- idx++;
- continue;
- }
- return tocmp;
- }
- return String();
-}
-
-void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(p_id==0);
- ERR_FAIL_COND(p_node_type==NODE_OUTPUT); //can't create output
- ERR_FAIL_COND( shader[p_type].node_map.has(p_id ) );
- ERR_FAIL_INDEX( p_node_type, NODE_TYPE_MAX );
- Node node;
-
- if (p_node_type==NODE_INPUT) {
- //see if it already exists
- for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- if (E->get().type==NODE_INPUT) {
- ERR_EXPLAIN("Only one input node can be added to the graph.");
- ERR_FAIL_COND(E->get().type==NODE_INPUT);
- }
- }
- }
- node.type=p_node_type;
- node.id=p_id;
-
- switch(p_node_type) {
- case NODE_INPUT: {} break; // all inputs (shader type dependent)
- case NODE_SCALAR_CONST: { node.param1=0;} break; //scalar constant
- case NODE_VEC_CONST: {node.param1=Vector3();} break; //vec3 constant
- case NODE_RGB_CONST: {node.param1=Color();} break; //rgb constant (shows a color picker instead)
- case NODE_XFORM_CONST: {node.param1=Transform();} break; // 4x4 matrix constant
- case NODE_TIME: {} break; // time in seconds
- case NODE_SCREEN_TEX: {Array arr; arr.push_back(0); arr.push_back(0); node.param2=arr;} break; // screen texture sampler (takes UV) (only usable in fragment shader)
- case NODE_SCALAR_OP: {node.param1=SCALAR_OP_ADD;} break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
- case NODE_VEC_OP: {node.param1=VEC_OP_ADD;} break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc)
- case NODE_VEC_SCALAR_OP: {node.param1=VEC_SCALAR_OP_MUL;} break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
- case NODE_RGB_OP: {node.param1=RGB_OP_SCREEN;} break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc.
- case NODE_XFORM_MULT: {} break; // mat4 x mat4
- case NODE_XFORM_VEC_MULT: {} break; // mat4 x vec3 mult (with no-translation option)
- case NODE_XFORM_VEC_INV_MULT: {} break; // mat4 x vec3 inverse mult (with no-translation option)
- case NODE_SCALAR_FUNC: {node.param1=SCALAR_FUNC_SIN;} break; // scalar function (sin: {} break; cos: {} break; etc)
- case NODE_VEC_FUNC: {node.param1=VEC_FUNC_NORMALIZE;} break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc)
- case NODE_VEC_LEN: {} break; // vec3 length
- case NODE_DOT_PROD: {} break; // vec3 . vec3 (dot product -> scalar output)
- case NODE_VEC_TO_SCALAR: {} break; // 1 vec3 input: {} break; 3 scalar outputs
- case NODE_SCALAR_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
- case NODE_VEC_TO_XFORM: {} break; // 3 scalar input: {} break; 1 vec3 output
- case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
- case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
- case NODE_VEC_INTERP: {} break; // vec3 interpolation (with optional curve)
- case NODE_COLOR_RAMP: { node.param1=PoolVector<Color>(); node.param2=PoolVector<real_t>();} break; // vec3 interpolation (with optional curve)
- case NODE_CURVE_MAP: { node.param1=PoolVector<Vector2>();} break; // vec3 interpolation (with optional curve)
- case NODE_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
- case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
- case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
- case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
- case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
- case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
- case NODE_DEFAULT_TEXTURE: {}; break;
- case NODE_OUTPUT: {} break; // output (shader type dependent)
- case NODE_COMMENT: {} break; // comment
- case NODE_TYPE_MAX: {};
- }
-
- shader[p_type].node_map[p_id]=node;
- _request_update();
-}
-
-void ShaderGraph::node_set_position(ShaderType p_type,int p_id, const Vector2& p_pos) {
- ERR_FAIL_INDEX(p_type,3);
-
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- shader[p_type].node_map[p_id].pos=p_pos;
- _request_update();
-
-}
-Vector2 ShaderGraph::node_get_position(ShaderType p_type,int p_id) const {
- ERR_FAIL_INDEX_V(p_type,3,Vector2());
-
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector2());
- return shader[p_type].node_map[p_id].pos;
-}
-
-
-void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
-
- ERR_FAIL_COND(p_id==0);
- ERR_FAIL_INDEX(p_type,3);
-
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
-
- //erase connections associated with node
- for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- if (E->key()==p_id)
- continue; //no self
-
- for (Map<int,SourceSlot>::Element *F=E->get().connections.front();F;) {
- Map<int,SourceSlot>::Element *N=F->next();
-
- if (F->get().id==p_id) {
- E->get().connections.erase(F);
- }
-
- F=N;
- }
- }
-
- shader[p_type].node_map.erase(p_id);
-
- _request_update();
-
-}
-
-
-
-void ShaderGraph::get_node_list(ShaderType p_type,List<int> *p_node_list) const {
-
- ERR_FAIL_INDEX(p_type,3);
-
- Map<int,Node>::Element *E = shader[p_type].node_map.front();
-
- while(E) {
-
- p_node_list->push_back(E->key());
- E=E->next();
- }
-}
-
-
-ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const {
-
- ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX);
-
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),NODE_TYPE_MAX);
- return shader[p_type].node_map[p_id].type;
-}
-
-
-Error ShaderGraph::connect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- ERR_FAIL_INDEX_V(p_type,3,ERR_INVALID_PARAMETER);
-
- ERR_FAIL_COND_V(p_src_id==p_dst_id, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
- NodeType type_src=shader[p_type].node_map[p_src_id].type;
- NodeType type_dst=shader[p_type].node_map[p_dst_id].type;
- ERR_FAIL_INDEX_V( p_src_slot, get_node_output_slot_count(get_mode(),p_type,type_src), ERR_INVALID_PARAMETER );
- ERR_FAIL_INDEX_V( p_dst_slot, get_node_input_slot_count(get_mode(),p_type,type_dst), ERR_INVALID_PARAMETER );
- ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(),p_type,type_src,p_src_slot) != get_node_input_slot_type(get_mode(),p_type,type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
-
-
- SourceSlot ts;
- ts.id=p_src_id;
- ts.slot=p_src_slot;
- shader[p_type].node_map[p_dst_id].connections[p_dst_slot]=ts;
- _request_update();
-
- return OK;
-}
-
-bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
-
- ERR_FAIL_INDEX_V(p_type,3,false);
-
- SourceSlot ts;
- ts.id=p_src_id;
- ts.slot=p_src_slot;
- return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
- shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts;
-}
-
-void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
- ERR_FAIL_INDEX(p_type,3);
-
- SourceSlot ts;
- ts.id=p_src_id;
- ts.slot=p_src_slot;
- if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
- shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts) {
- shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot);
-
- }
- _request_update();
-
-}
-
-void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_connections) const {
-
- ERR_FAIL_INDEX(p_type,3);
-
- for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
-
- Connection c;
- c.dst_id=E->key();
- c.dst_slot=F->key();
- c.src_id=F->get().id;
- c.src_slot=F->get().slot;
- p_connections->push_back(c);
- }
- }
-}
-
-bool ShaderGraph::is_slot_connected(ShaderGraph::ShaderType p_type, int p_dst_id, int slot_id)
-{
- for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
- for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
-
- if (p_dst_id == E->key() && slot_id==F->key())
- return true;
- }
- }
- return false;
-}
-
-
-void ShaderGraph::clear(ShaderType p_type) {
-
- ERR_FAIL_INDEX(p_type,3);
- shader[p_type].node_map.clear();
- Node out;
- out.pos=Vector2(300,300);
- out.type=NODE_OUTPUT;
- shader[p_type].node_map.insert(0,out);
-
- _request_update();
-
-}
-
-
-void ShaderGraph::scalar_const_node_set_value(ShaderType p_type,int p_id,float p_value) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_CONST);
- n.param1=p_value;
- _request_update();
-
-}
-
-float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_CONST,0);
- return n.param1;
-}
-
-void ShaderGraph::vec_const_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_CONST);
- n.param1=p_value;
- _request_update();
-
-
-}
-Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Vector3());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_CONST,Vector3());
- return n.param1;
-
-}
-
-void ShaderGraph::rgb_const_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_RGB_CONST);
- n.param1=p_value;
- _request_update();
-
-}
-Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Color());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_RGB_CONST,Color());
- return n.param1;
-
-}
-
-void ShaderGraph::xform_const_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_XFORM_CONST);
- n.param1=p_value;
- _request_update();
-
-}
-Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Transform());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_XFORM_CONST,Transform());
- return n.param1;
-
-}
-
-void ShaderGraph::texture_node_set_filter_size(ShaderType p_type,int p_id,int p_size){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
- Array arr = n.param2;
- arr[0]=p_size;
- n.param2=arr;
- _request_update();
-
-}
-int ShaderGraph::texture_node_get_filter_size(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
- Array arr = n.param2;
- return arr[0];
-
-}
-
-void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type,float p_id,float p_strength){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
- Array arr = n.param2;
- arr[1]=p_strength;
- n.param2=arr;
- _request_update();
-
-}
-float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
- Array arr = n.param2;
- return arr[1];
-}
-
-void ShaderGraph::duplicate_nodes(ShaderType p_which, List<int> &p_nodes)
-{
- //Create new node IDs
- Map<int,int> duplicates = Map<int,int>();
- int i=1;
- for(List<int>::Element *E=p_nodes.front();E; E=E->next()) {
- while (shader[p_which].node_map.has(i))
- i++;
- duplicates.insert(E->get(), i);
- i++;
- }
-
- for(List<int>::Element *E = p_nodes.front();E; E=E->next()) {
-
- const Node &n=shader[p_which].node_map[E->get()];
- Node nn=n;
- nn.id=duplicates.find(n.id)->get();
- nn.pos += Vector2(0,100);
- for (Map<int,SourceSlot>::Element *C=nn.connections.front();C;C=C->next()) {
- SourceSlot &c=C->get();
- if (p_nodes.find(c.id))
- c.id=duplicates.find(c.id)->get();
- }
- shader[p_which].node_map[nn.id]=nn;
- }
- _request_update();
-}
-
-List<int> ShaderGraph::generate_ids(ShaderType p_type, int count)
-{
- List<int> ids = List<int>();
- int i=1;
- while (ids.size() < count) {
- while (shader[p_type].node_map.has(i))
- i++;
- ids.push_back(i);
- i++;
- }
- return ids;
-}
-
-
-void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_OP);
- n.param1=p_op;
- _request_update();
-
-}
-ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_OP,SCALAR_MAX_OP);
- int op = n.param1;
- return ScalarOp(op);
-
-}
-
-
-void ShaderGraph::vec_op_node_set_op(ShaderType p_type,float p_id,VecOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_OP);
- n.param1=p_op;
- _request_update();
-
-}
-ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_OP,VEC_MAX_OP);
- int op = n.param1;
- return VecOp(op);
-
-}
-
-
-void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type,float p_id,VecScalarOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_SCALAR_OP);
- n.param1=p_op;
- _request_update();
-
-}
-ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,VEC_SCALAR_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_SCALAR_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_SCALAR_OP,VEC_SCALAR_MAX_OP);
- int op = n.param1;
- return VecScalarOp(op);
-
-}
-
-void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_RGB_OP);
- n.param1=p_op;
-
- _request_update();
-
-}
-ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,RGB_MAX_OP);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),RGB_MAX_OP);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,RGB_MAX_OP);
- int op = n.param1;
- return RGBOp(op);
-
-}
-
-
-void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT);
- n.param1=p_no_translation;
- _request_update();
-
-}
-bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,false);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),false);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT,false);
- return n.param1;
-
-}
-
-void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,ScalarFunc p_func){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC);
- int func = p_func;
- ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
- n.param1=func;
- _request_update();
-
-}
-ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_FUNC);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_FUNC);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_FUNC,SCALAR_MAX_FUNC);
- int func = n.param1;
- return ScalarFunc(func);
-}
-
-void ShaderGraph::default_set_value(ShaderGraph::ShaderType p_which, int p_id, int p_param, const Variant &p_value)
-{
- ERR_FAIL_INDEX(p_which,3);
- ERR_FAIL_COND(!shader[p_which].node_map.has(p_id));
- Node& n = shader[p_which].node_map[p_id];
- if(p_value.get_type()==Variant::NIL)
- n.defaults.erase(n.defaults.find(p_param));
- else
- n.defaults[p_param]=p_value;
-
- _request_update();
-
-}
-
-Variant ShaderGraph::default_get_value(ShaderGraph::ShaderType p_which, int p_id, int p_param)
-{
- ERR_FAIL_INDEX_V(p_which,3,Variant());
- ERR_FAIL_COND_V(!shader[p_which].node_map.has(p_id),Variant());
- const Node& n = shader[p_which].node_map[p_id];
-
- if (!n.defaults.has(p_param))
- return Variant();
- return n.defaults[p_param];
-}
-
-
-
-void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_FUNC);
- int func = p_func;
- ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
- n.param1=func;
-
- _request_update();
-
-}
-ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_FUNC);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_FUNC);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_FUNC,VEC_MAX_FUNC);
- int func = n.param1;
- return VecFunc(func);
-}
-
-void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type,int p_id,const PoolVector<Color>& p_colors, const PoolVector<real_t>& p_offsets){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_colors;
- n.param2=p_offsets;
- _request_update();
-
-}
-
-PoolVector<Color> ShaderGraph::color_ramp_node_get_colors(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,PoolVector<Color>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),PoolVector<Color>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
-
-
-}
-
-PoolVector<real_t> ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,PoolVector<real_t>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),PoolVector<real_t>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param2;
-
-}
-
-
-void ShaderGraph::curve_map_node_set_points(ShaderType p_type,int p_id,const PoolVector<Vector2>& p_points) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_points;
- _request_update();
-
-}
-
-PoolVector<Vector2> ShaderGraph::curve_map_node_get_points(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,PoolVector<Vector2>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),PoolVector<Vector2>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
-
-}
-
-
-
-void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- ERR_FAIL_COND(!p_name.is_valid_identifier());
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT);
-
- n.param1="";
- n.param1=_find_unique_name(p_name);
- _request_update();
-
-}
-String ShaderGraph::input_node_get_name(ShaderType p_type,int p_id){
-
- ERR_FAIL_INDEX_V(p_type,3,String());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT,String());
- return n.param1;
-}
-
-
-void ShaderGraph::scalar_input_node_set_value(ShaderType p_type,int p_id,float p_value) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT);
- n.param2=p_value;
- _request_update();
-
-}
-
-float ShaderGraph::scalar_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,0);
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT,0);
-
- return n.param2;
-}
-
-void ShaderGraph::vec_input_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_VEC_INPUT);
-
- n.param2=p_value;
- _request_update();
-
-}
-Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Vector3());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_VEC_INPUT,Vector3());
- return n.param2;
-}
-
-void ShaderGraph::rgb_input_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_RGB_INPUT);
- n.param2=p_value;
- _request_update();
-
-}
-Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Color());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_RGB_INPUT,Color());
- return n.param2;
-}
-
-void ShaderGraph::xform_input_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_XFORM_INPUT);
- n.param2=p_value;
- _request_update();
-
-}
-Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Transform());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_XFORM_INPUT,Transform());
- return n.param2;
-}
-
-
-void ShaderGraph::texture_input_node_set_value(ShaderType p_type,int p_id,const Ref<Texture>& p_texture) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT);
- n.param2=p_texture;
- _request_update();
-
-}
-
-Ref<Texture> ShaderGraph::texture_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Ref<Texture>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<Texture>());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT,Ref<Texture>());
- return n.param2;
-}
-
-void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type,int p_id,const Ref<CubeMap>& p_cubemap){
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_CUBEMAP_INPUT);
- n.param2=p_cubemap;
- _request_update();
-
-}
-
-Ref<CubeMap> ShaderGraph::cubemap_input_node_get_value(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,Ref<CubeMap>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<CubeMap>());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_CUBEMAP_INPUT,Ref<CubeMap>());
- return n.param2;
-
-}
-
-
-void ShaderGraph::comment_node_set_text(ShaderType p_type,int p_id,const String& p_comment) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND(n.type!=NODE_COMMENT);
- n.param1=p_comment;
-
-}
-
-String ShaderGraph::comment_node_get_text(ShaderType p_type,int p_id) const{
-
- ERR_FAIL_INDEX_V(p_type,3,String());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
- const Node& n = shader[p_type].node_map[p_id];
- ERR_FAIL_COND_V(n.type!=NODE_COMMENT,String());
- return n.param1;
-
-}
-
-void ShaderGraph::_request_update() {
-
- if (_pending_update_shader)
- return;
-
- _pending_update_shader=true;
- call_deferred("_update_shader");
-
-}
-
-Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
-
- ERR_FAIL_INDEX_V(p_type,3,Variant());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Variant());
- const Node& n = shader[p_type].node_map[p_id];
- Dictionary s;
- s["position"]=n.pos;
- s["param1"]=n.param1;
- s["param2"]=n.param2;
- Array keys;
- for (Map<int,Variant>::Element *E=n.defaults.front();E;E=E->next()) {
- keys.append(E->key());
- s[E->key()]=E->get();
- }
- s["default_keys"]=keys;
- return s;
-
-}
-void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_state) {
-
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- Dictionary d = p_state;
- ERR_FAIL_COND(!d.has("position"));
- ERR_FAIL_COND(!d.has("param1"));
- ERR_FAIL_COND(!d.has("param2"));
- ERR_FAIL_COND(!d.has("default_keys"));
-
- n.pos=d["position"];
- n.param1=d["param1"];
- n.param2=d["param2"];
- Array keys = d["default_keys"];
- for(int i=0;i<keys.size();i++) {
- n.defaults[keys[i]]=d[keys[i]];
- }
-}
-
-ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
-
- //shader = VisualServer::get_singleton()->shader_create();
- _pending_update_shader=false;
-
- Node input;
- input.id=1;
- input.pos=Vector2(50,40);
- input.type=NODE_INPUT;
-
- Node output;
- output.id=0;
- output.pos=Vector2(350,40);
- output.type=NODE_OUTPUT;
-
- for(int i=0;i<3;i++) {
-
- shader[i].node_map.insert(0,output);
- shader[i].node_map.insert(1,input);
- }
-}
-
-ShaderGraph::~ShaderGraph() {
-
- //VisualServer::get_singleton()->free(shader);
-}
-
-
-const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
- //material vertex in
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","SRC_VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","SRC_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","SRC_TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"BinormalF","SRC_BINORMALF","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","SRC_COLOR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","SRC_ALPHA","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","SRC_UV2","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ModelviewMatrix","MODELVIEW_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InstanceID","INSTANCE_ID","",SLOT_TYPE_SCALAR,SLOT_IN},
-
- //material vertex out
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"SpecExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //pixel vertex in
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","vec3(UV2,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- //pixel vertex out
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Discard","DISCARD",">0.5",SLOT_TYPE_SCALAR,SLOT_OUT},
- //light in
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDir","LIGHT_DIR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDiffuse","LIGHT_DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightSpecular","LIGHT_SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"EyeVec","EYE_VEC","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Diffuse","DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"SpecExp","SPECULAR_EXP","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN},
- //light out
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Shadow", "SHADOW", "",SLOT_TYPE_VEC, SLOT_OUT },
- //canvas item vertex in
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","vec3(SRC_VERTEX,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ExtraMatrix","EXTRA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN},
- //canvas item vertex out
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","VERTEX",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //canvas item fragment in
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","SRC_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","SRC_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"UVScreen","vec3(SCREEN_UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Position","POSITION","",SLOT_TYPE_VEC,SLOT_IN},
- //canvas item fragment out
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //canvas item light in
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"UV","vec3(UV,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightColor","LIGHT_COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightAlpha","LIGHT_COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightHeight","LIGHT_HEIGHT","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowColor","LIGHT_SHADOW.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowAlpha","LIGHT_SHADOW.a","",SLOT_TYPE_SCALAR,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"TexPixelSize","vec3(TEXTURE_PIXEL_SIZE,0)","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"Position","POSITION","",SLOT_TYPE_VEC,SLOT_IN},
- //canvas item light out
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightColor","LIGHT.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"LightAlpha","LIGHT.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowColor","SHADOW.rgb","",SLOT_TYPE_VEC,SLOT_OUT},
- {MODE_CANVAS_ITEM,SHADER_TYPE_LIGHT,"ShadowAlpha","SHADOW.a","",SLOT_TYPE_SCALAR,SLOT_OUT},
- //end
- {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
-
-
-
-};
-
-void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_type==iop->shader_type) {
-
- SlotInfo si;
- si.dir=iop->dir;
- si.name=iop->name;
- si.type=iop->slot_type;
- r_slots->push_back(si);
- }
- iop++;
- }
-}
-
-
-const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
-
- {NODE_SCALAR_CONST,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, //scalar constant
- {NODE_VEC_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //vec3 constant
- {NODE_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, //rgb constant (shows a color picker instead)
- {NODE_XFORM_CONST,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // 4x4 matrix constant
- {NODE_TIME,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // time in seconds
- {NODE_SCREEN_TEX,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // screen texture sampler (takes UV) (only usable in fragment shader)
- {NODE_SCALAR_OP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_SCALAR_OP,{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4
- {NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option)
- {NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
- {NODE_SCALAR_FUNC,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_FUNC,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc)
- {NODE_VEC_LEN,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 length
- {NODE_DOT_PROD,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 . vec3 (dot product -> scalar output)
- {NODE_VEC_TO_SCALAR,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR}}, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs
- {NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output
- {NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve)
- {NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation (with optional curve)
- {NODE_COLOR_RAMP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
- {NODE_CURVE_MAP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
- {NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material)
- {NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material)
- {NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // color uniform (assignable in material)
- {NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material)
- {NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material)
- {NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
- {NODE_DEFAULT_TEXTURE,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
- {NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
- {NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}}
-};
-
-int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type) {
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_OUT)
- pc++;
- }
- iop++;
- }
- return pc;
- } else if (p_type==NODE_VEC_TO_XFORM){
- return 4;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return 1;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- int pc=0;
- for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
- if (nsi->ins[i]==SLOT_MAX)
- break;
- pc++;
- }
- return pc;
- }
-
- nsi++;
- }
-
- return 0;
-
- }
-}
-
-int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type){
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_IN)
- pc++;
- }
- iop++;
- }
- return pc;
- } else if (p_type==NODE_VEC_TO_XFORM){
- return 1;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return 4;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- int pc=0;
- for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
- if (nsi->outs[i]==SLOT_MAX)
- break;
- pc++;
- }
- return pc;
- }
-
- nsi++;
- }
-
- return 0;
-
- }
-}
-ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_OUT) {
- if (pc==p_idx)
- return iop->slot_type;
- pc++;
- }
- }
- iop++;
- }
- ERR_FAIL_V(SLOT_MAX);
- } else if (p_type==NODE_VEC_TO_XFORM){
- return SLOT_TYPE_VEC;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return SLOT_TYPE_XFORM;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
-
- if (nsi->ins[i]==SLOT_MAX)
- break;
- if (i==p_idx)
- return nsi->ins[i];
- }
- }
-
- nsi++;
- }
-
- ERR_FAIL_V(SLOT_MAX);
-
- }
-}
-ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){
-
- if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int pc=0;
- while(iop->name) {
- if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
-
- if (iop->dir==SLOT_IN) {
- if (pc==p_idx)
- return iop->slot_type;
- pc++;
- }
- }
- iop++;
- }
- ERR_FAIL_V(SLOT_MAX);
- } else if (p_type==NODE_VEC_TO_XFORM){
- return SLOT_TYPE_XFORM;
- } else if (p_type==NODE_XFORM_TO_VEC){
- return SLOT_TYPE_VEC;
- } else {
-
- const NodeSlotInfo*nsi=&node_slot_info[0];
- while(nsi->type!=NODE_TYPE_MAX) {
-
- if (nsi->type==p_type) {
- for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
- if (nsi->outs[i]==SLOT_MAX)
- break;
- if (i==p_idx)
- return nsi->outs[i];
- }
- }
-
- nsi++;
- }
-
- ERR_FAIL_V(SLOT_MAX);
- }
-}
-
-
-
-
-
-void ShaderGraph::_update_shader() {
-
-
- String code[3];
-
- List<StringName> names;
- get_default_texture_param_list(&names);
-
- for (List<StringName>::Element *E=names.front();E;E=E->next()) {
-
- set_default_texture_param(E->get(),Ref<Texture>());
- }
-
-
- for(int i=0;i<3;i++) {
-
- int idx=0;
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
-
- E->get().sort_order=idx++;
- }
- //simple method for graph solving using bubblesort derived algorithm
- int iters=0;
- int iter_max=shader[i].node_map.size()*shader[i].node_map.size();
-
- while(true) {
- if (iters>iter_max)
- break;
-
- int swaps=0;
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
-
- for(Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
-
- //this is kinda slow, could be sped up
- Map<int,Node>::Element *G = shader[i].node_map.find(F->get().id);
- ERR_FAIL_COND(!G);
- if (G->get().sort_order > E->get().sort_order) {
-
- SWAP(G->get().sort_order,E->get().sort_order);
- swaps++;
- }
- }
- }
-
- iters++;
- if (swaps==0) {
- iters=0;
- break;
- }
- }
-
- if (iters>0) {
-
- shader[i].error=GRAPH_ERROR_CYCLIC;
- continue;
- }
-
- Vector<Node*> order;
- order.resize(shader[i].node_map.size());
-
- for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
-
- order[E->get().sort_order]=&E->get();
- }
-
- //generate code for the ordered graph
- bool failed=false;
-
- if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
- code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);\n";
- code[i]+="float ALPHA_OUT=0;\n";
- }
-
-
- Map<String,String> inputs_xlate;
- Map<String,String> input_names_xlate;
- Set<String> inputs_used;
-
- for(int j=0;j<order.size();j++) {
-
- Node *n=order[j];
- if (n->type==NODE_INPUT) {
-
- const InOutParamInfo* iop = &inout_param_info[0];
- int idx=0;
- while(iop->name) {
- if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_IN==iop->dir) {
-
- const char *typestr[4]={"float","vec3","mat4","texture"};
-
- String vname=("nd"+itos(n->id)+"sl"+itos(idx));
- inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n";
- input_names_xlate[vname]=iop->variable;
- idx++;
- }
- iop++;
- }
-
- } else if (n->type==NODE_OUTPUT) {
-
-
- bool use_alpha=false;
- const InOutParamInfo* iop = &inout_param_info[0];
- int idx=0;
- while(iop->name) {
- if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_OUT==iop->dir) {
-
- if (n->connections.has(idx)) {
- String iname=("nd"+itos(n->connections[idx].id)+"sl"+itos(n->connections[idx].slot));
- if (node_get_type(ShaderType(i),n->connections[idx].id)==NODE_INPUT)
- inputs_used.insert(iname);
- code[i]+=String(iop->variable)+"="+iname+String(iop->postfix)+";\n";
- if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha")
- use_alpha=true;
- }
- idx++;
- }
- iop++;
- }
-
- if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
-
- if (use_alpha) {
- code[i]+="DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n";
- } else {
- code[i]+="DIFFUSE=DIFFUSE_OUT;\n";
- }
- }
-
- } else {
- Vector<String> inputs;
- int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
- for(int k=0;k<max;k++) {
- String iname;
- if (!n->connections.has(k)) {
- iname="nd"+itos(n->id)+"sl"+itos(k)+"def";
- } else {
- iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
- if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
- inputs_used.insert(iname);
- }
-
- }
- inputs.push_back(iname);
- }
-
- if (failed)
- break;
-
- if (n->type==NODE_TEXTURE_INPUT || n->type==NODE_CUBEMAP_INPUT) {
-
- set_default_texture_param(n->param1,n->param2);
-
- }
- _add_node_code(ShaderType(i),n,inputs,code[i]);
- }
-
- }
-
- if (failed)
- continue;
-
-
- for(Set<String>::Element *E=inputs_used.front();E;E=E->next()) {
-
- ERR_CONTINUE( !inputs_xlate.has(E->get()));
- code[i]=inputs_xlate[E->get()]+code[i];
- String name=input_names_xlate[E->get()];
-
- if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_MATERIAL) {
- if (name==("SRC_COLOR"))
- code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
- if (name==("SRC_ALPHA"))
- code[i]="float SRC_ALPHA=COLOR.a;\n"+code[i];
- if (name==("SRC_UV"))
- code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
- if (name==("SRC_UV2"))
- code[i]="float SRC_UV2=vec3(UV2,0);\n"+code[i];
- } else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
- if (name==("IN_NORMAL"))
- code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i];
- } else if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_CANVAS_ITEM) {
- if (name==("SRC_COLOR"))
- code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
- if (name==("SRC_UV"))
- code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
- }
-
- }
-
-
-
- shader[i].error=GRAPH_OK;
-
- }
-
- bool all_ok=true;
- for(int i=0;i<3;i++) {
- if (shader[i].error!=GRAPH_OK)
- all_ok=false;
- }
-
- /*print_line("VERTEX: \n"+code[0]);
- print_line("FRAGMENT: \n"+code[1]);
- print_line("LIGHT: \n"+code[2]);*/
-
- if (all_ok) {
- set_code(code[0],code[1],code[2]);
- }
- //do shader here
-
- _pending_update_shader=false;
- emit_signal(SceneStringNames::get_singleton()->updated);
-}
-
-void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds) {
-
- float geometry[4][4];
- float tmp1[4][4];
- float tmp2[4][4];
- float deltas[4][4];
- double x, dx, dx2, dx3;
- double y, dy, dy2, dy3;
- double d, d2, d3;
- int lastx, lasty;
- int newx, newy;
- int ntimes;
- int i,j;
-
- int xmax=255;
- int ymax=255;
-
- /* construct the geometry matrix from the segment */
- for (i = 0; i < 4; i++) {
- geometry[i][2] = 0;
- geometry[i][3] = 0;
- }
-
- geometry[0][0] = (p_a[0] * xmax);
- geometry[1][0] = (p_b[0] * xmax);
- geometry[2][0] = (p_c[0] * xmax);
- geometry[3][0] = (p_d[0] * xmax);
-
- geometry[0][1] = (p_a[1] * ymax);
- geometry[1][1] = (p_b[1] * ymax);
- geometry[2][1] = (p_c[1] * ymax);
- geometry[3][1] = (p_d[1] * ymax);
-
- /* subdivide the curve ntimes (1000) times */
- ntimes = 4 * xmax;
- /* ntimes can be adjusted to give a finer or coarser curve */
- d = 1.0 / ntimes;
- d2 = d * d;
- d3 = d * d * d;
-
- /* construct a temporary matrix for determining the forward differencing deltas */
- tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
- tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
- tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
- tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
-
- /* compose the basis and geometry matrices */
-
- static const float CR_basis[4][4] = {
- { -0.5, 1.5, -1.5, 0.5 },
- { 1.0, -2.5, 2.0, -0.5 },
- { -0.5, 0.0, 0.5, 0.0 },
- { 0.0, 1.0, 0.0, 0.0 },
- };
-
- for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
- {
- tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
- CR_basis[i][1] * geometry[1][j] +
- CR_basis[i][2] * geometry[2][j] +
- CR_basis[i][3] * geometry[3][j]);
- }
- }
- /* compose the above results to get the deltas matrix */
-
- for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
- {
- deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
- tmp2[i][1] * tmp1[1][j] +
- tmp2[i][2] * tmp1[2][j] +
- tmp2[i][3] * tmp1[3][j]);
- }
- }
-
-
- /* extract the x deltas */
- x = deltas[0][0];
- dx = deltas[1][0];
- dx2 = deltas[2][0];
- dx3 = deltas[3][0];
-
- /* extract the y deltas */
- y = deltas[0][1];
- dy = deltas[1][1];
- dy2 = deltas[2][1];
- dy3 = deltas[3][1];
-
-
- lastx = CLAMP (x, 0, xmax);
- lasty = CLAMP (y, 0, ymax);
-
- p_heights[lastx] = lasty;
- p_useds[lastx] = true;
-
- /* loop over the curve */
- for (i = 0; i < ntimes; i++)
- {
- /* increment the x values */
- x += dx;
- dx += dx2;
- dx2 += dx3;
-
- /* increment the y values */
- y += dy;
- dy += dy2;
- dy2 += dy3;
-
- newx = CLAMP ((Math::round (x)), 0, xmax);
- newy = CLAMP ((Math::round (y)), 0, ymax);
-
- /* if this point is different than the last one...then draw it */
- if ((lastx != newx) || (lasty != newy))
- {
- p_useds[newx]=true;
- p_heights[newx]=newy;
- }
-
- lastx = newx;
- lasty = newy;
- }
-}
-
-
-void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
-
-
- const char *typestr[4]={"float","vec3","mat4","texture"};
-#define OUTNAME(id, slot) (String(typestr[get_node_output_slot_type(get_mode(), p_type, p_node->type, slot)]) + " " + ("nd" + itos(id) + "sl" + itos(slot)))
-#define OUTVAR(id, slot) ("nd" + itos(id) + "sl" + itos(slot))
-#define DEF_VEC(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- Vector3 v = p_node->defaults[slot]; \
- code += String(typestr[1]) + " " + p_inputs[slot] + "=vec3(" + v + ");\n"; \
- }
-#define DEF_SCALAR(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- double v = p_node->defaults[slot]; \
- code += String(typestr[0]) + " " + p_inputs[slot] + "=" + rtos(v) + ";\n"; \
- }
-#define DEF_COLOR(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- Color col = p_node->defaults[slot]; \
- code += String(typestr[1]) + " " + p_inputs[slot] + "=vec3(" + rtos(col.r) + "," + rtos(col.g) + "," + rtos(col.b) + ");\n"; \
- }
-#define DEF_MATRIX(slot) \
- if (p_inputs[slot].ends_with("def")) { \
- Transform xf = p_node->defaults[slot]; \
- code += String(typestr[2]) + " " + p_inputs[slot] + "=mat4(\n"; \
- code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(0).x) + "," + rtos(xf.basis.get_axis(0).y) + "," + rtos(xf.basis.get_axis(0).z) + "),0),\n"; \
- code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(1).x) + "," + rtos(xf.basis.get_axis(1).y) + "," + rtos(xf.basis.get_axis(1).z) + "),0),\n"; \
- code += "\tvec4(vec3(" + rtos(xf.basis.get_axis(2).x) + "," + rtos(xf.basis.get_axis(2).y) + "," + rtos(xf.basis.get_axis(2).z) + "),0),\n"; \
- code += "\tvec4(vec3(" + rtos(xf.origin.x) + "," + rtos(xf.origin.y) + "," + rtos(xf.origin.z) + "),1)\n"; \
- code += ");\n"; \
- }
-
- switch(p_node->type) {
-
- case NODE_INPUT: {
-
-
- }break;
- case NODE_SCALAR_CONST: {
-
- double scalar = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"="+rtos(scalar)+";\n";
- }break;
- case NODE_VEC_CONST: {
- Vector3 vec = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(vec.x)+","+rtos(vec.y)+","+rtos(vec.z)+");\n";
- }break;
- case NODE_RGB_CONST: {
- Color col = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";
- code+=OUTNAME(p_node->id,1)+"="+rtos(col.a)+";\n";
- }break;
- case NODE_XFORM_CONST: {
-
- Transform xf = p_node->param1;
- code+=OUTNAME(p_node->id,0)+"=mat4(\n";
- code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";
- code+=");";
-
- }break;
- case NODE_TIME: {
- code+=OUTNAME(p_node->id,0)+"=TIME;\n";
- }break;
- case NODE_SCREEN_TEX: {
- DEF_VEC(0);
- code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+".xy);\n";
- }break;
- case NODE_SCALAR_OP: {
- DEF_SCALAR(0);
- DEF_SCALAR(1);
- int op = p_node->param1;
- String optxt;
- switch(op) {
-
- case SCALAR_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
- case SCALAR_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
- case SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
- case SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
- case SCALAR_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case SCALAR_OP_ATAN2: optxt = "atan2("+p_inputs[0]+","+p_inputs[1]+");"; break;
-
- }
- code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
-
- }break;
- case NODE_VEC_OP: {
- DEF_VEC(0);
- DEF_VEC(1);
- int op = p_node->param1;
- String optxt;
- switch(op) {
- case VEC_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
- case VEC_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
- case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
- case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
- case VEC_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
- case VEC_OP_CROSS: optxt = "cross("+p_inputs[0]+","+p_inputs[1]+");"; break;
- }
- code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
-
- }break;
- case NODE_VEC_SCALAR_OP: {
- DEF_VEC(0);
- DEF_SCALAR(1);
- int op = p_node->param1;
- String optxt;
- switch(op) {
- case VEC_SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
- case VEC_SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
- case VEC_SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
- }
- code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
-
- }break;
- case NODE_RGB_OP: {
- DEF_COLOR(0);
- DEF_COLOR(1);
-
- int op = p_node->param1;
- static const char*axisn[3]={"x","y","z"};
- switch(op) {
- case RGB_OP_SCREEN: {
-
- code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n";
- } break;
- case RGB_OP_DIFFERENCE: {
-
- code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
- } break;
- case RGB_OP_DARKEN: {
-
- code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n";
- } break;
- case RGB_OP_LIGHTEN: {
-
- code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n";
-
- } break;
- case RGB_OP_OVERLAY: {
-
- code += OUTNAME(p_node->id,0)+";\n";
- for(int i=0;i<3;i++) {
- code += "{\n";
- code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
- code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
- code += "\tif (base < 0.5) {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n";
- code += "\t} else {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
- code += "\t}\n";
- code += "}\n";
- }
-
- } break;
- case RGB_OP_DODGE: {
-
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n";
-
- } break;
- case RGB_OP_BURN: {
-
- code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n";
- } break;
- case RGB_OP_SOFT_LIGHT: {
-
- code += OUTNAME(p_node->id,0)+";\n";
- for(int i=0;i<3;i++) {
- code += "{\n";
- code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
- code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
- code += "\tif (base < 0.5) {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n";
- code += "\t} else {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n";
- code += "\t}\n";
- code += "}\n";
- }
-
- } break;
- case RGB_OP_HARD_LIGHT: {
-
- code += OUTNAME(p_node->id,0)+";\n";
- for(int i=0;i<3;i++) {
- code += "{\n";
- code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
- code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
- code += "\tif (base < 0.5) {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n";
- code += "\t} else {\n";
- code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n";
- code += "\t}\n";
- code += "}\n";
- }
-
- } break;
- }
- }break;
- case NODE_XFORM_MULT: {
- DEF_MATRIX(0);
- DEF_MATRIX(1);
-
- code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
-
- }break;
- case NODE_XFORM_VEC_MULT: {
- DEF_MATRIX(0);
- DEF_VEC(1);
-
- bool no_translation = p_node->param1;
- if (no_translation) {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",0)).xyz;\n";
- } else {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",1)).xyz;\n";
- }
-
- }break;
- case NODE_XFORM_VEC_INV_MULT: {
- DEF_VEC(0);
- DEF_MATRIX(1);
- bool no_translation = p_node->param1;
- if (no_translation) {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
- } else {
- code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",1)).xyz;\n";
- }
- }break;
- case NODE_SCALAR_FUNC: {
- DEF_SCALAR(0);
- static const char*scalar_func_id[SCALAR_MAX_FUNC]={
- "sin($)",
- "cos($)",
- "tan($)",
- "asin($)",
- "acos($)",
- "atan($)",
- "sinh($)",
- "cosh($)",
- "tanh($)",
- "log($)",
- "exp($)",
- "sqrt($)",
- "abs($)",
- "sign($)",
- "floor($)",
- "round($)",
- "ceil($)",
- "fract($)",
- "min(max($,0),1)",
- "-($)",
- };
-
- int func = p_node->param1;
- ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
- code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n";
-
- } break;
- case NODE_VEC_FUNC: {
- DEF_VEC(0);
- static const char*vec_func_id[VEC_MAX_FUNC]={
- "normalize($)",
- "max(min($,vec3(1,1,1)),vec3(0,0,0))",
- "-($)",
- "1.0/($)",
- "",
- "",
- };
-
-
- int func = p_node->param1;
- ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
- if (func==VEC_FUNC_RGB2HSV) {
- code += OUTNAME(p_node->id,0)+";\n";
- code+="{\n";
- code+="\tvec3 c = "+p_inputs[0]+";\n";
- code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
- code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
- code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
- code+="\tfloat d = q.x - min(q.w, q.y);\n";
- code+="\tfloat e = 1.0e-10;\n";
- code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
- code+="}\n";
- } else if (func==VEC_FUNC_HSV2RGB) {
- code += OUTNAME(p_node->id,0)+";\n";
- code+="{\n";
- code+="\tvec3 c = "+p_inputs[0]+";\n";
- code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
- code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
- code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
- code+="}\n";
-
- } else {
- code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n";
- }
- }break;
- case NODE_VEC_LEN: {
- DEF_VEC(0);
-
- code += OUTNAME(p_node->id,0)+"=length("+p_inputs[0]+");\n";
-
- }break;
- case NODE_DOT_PROD: {
- DEF_VEC(0);
- DEF_VEC(1);
- code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
-
- }break;
- case NODE_VEC_TO_SCALAR: {
- DEF_VEC(0);
- code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
- code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
- code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
-
- }break;
- case NODE_SCALAR_TO_VEC: {
- DEF_SCALAR(0);
- DEF_SCALAR(1);
- DEF_SCALAR(2);
- code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
-
- }break;
- case NODE_VEC_TO_XFORM: {
- DEF_VEC(0);
- DEF_VEC(1);
- DEF_VEC(2);
- DEF_VEC(3);
- code += OUTNAME(p_node->id, 0) + "=mat4(" +
- "vec4(" + p_inputs[0] + ".x," + p_inputs[0] + ".y," + p_inputs[0] + ".z, 0.0),"
- "vec4(" + p_inputs[1] + ".x," + p_inputs[1] + ".y," + p_inputs[1] + ".z, 0.0),"
- "vec4(" + p_inputs[2] + ".x," + p_inputs[2] + ".y," + p_inputs[2] + ".z, 0.0),"
- "vec4(" + p_inputs[3] + ".x," + p_inputs[3] + ".y," + p_inputs[3] + ".z, 1.0));\n";
-
- }break;
- case NODE_XFORM_TO_VEC: {
- DEF_MATRIX(0);
- code += OUTNAME(p_node->id, 0) + ";\n";
- code += OUTNAME(p_node->id, 1) + ";\n";
- code += OUTNAME(p_node->id, 2) + ";\n";
- code += OUTNAME(p_node->id, 3) + ";\n";
- code += "{\n";
- code += "\tvec4 xform_row_01=" + p_inputs[0] + ".x;\n";
- code += "\tvec4 xform_row_02=" + p_inputs[0] + ".y;\n";
- code += "\tvec4 xform_row_03=" + p_inputs[0] + ".z;\n";
- code += "\tvec4 xform_row_04=" + p_inputs[0] + ".w;\n";
- code += "\t" + OUTVAR(p_node->id, 0) + "=vec3(xform_row_01.x, xform_row_01.y, xform_row_01.z);\n";
- code += "\t" + OUTVAR(p_node->id, 1) + "=vec3(xform_row_02.x, xform_row_02.y, xform_row_02.z);\n";
- code += "\t" + OUTVAR(p_node->id, 2) + "=vec3(xform_row_03.x, xform_row_03.y, xform_row_03.z);\n";
- code += "\t" + OUTVAR(p_node->id, 3) + "=vec3(xform_row_04.x, xform_row_04.y, xform_row_04.z);\n";
- code += "}\n";
- }break;
- case NODE_SCALAR_INTERP: {
- DEF_SCALAR(0);
- DEF_SCALAR(1);
- DEF_SCALAR(2);
-
- code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
-
- }break;
- case NODE_VEC_INTERP: {
- DEF_VEC(0);
- DEF_VEC(1);
- DEF_SCALAR(2);
- code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
-
- }break;
- case NODE_COLOR_RAMP: {
- DEF_SCALAR(0);
-
- static const int color_ramp_len=512;
- PoolVector<uint8_t> cramp;
- cramp.resize(color_ramp_len*4);
- {
-
- PoolVector<Color> colors=p_node->param1;
- PoolVector<real_t> offsets=p_node->param2;
- int cc =colors.size();
- PoolVector<uint8_t>::Write crw = cramp.write();
- PoolVector<Color>::Read cr = colors.read();
- PoolVector<real_t>::Read ofr = offsets.read();
-
- int at=0;
- Color color_at(0,0,0,1);
- for(int i=0;i<=cc;i++) {
-
- int pos;
- Color to;
- if (i==cc) {
- if (at==color_ramp_len)
- break;
- pos=color_ramp_len;
- to=Color(1,1,1,1);
- } else {
- to=cr[i];
- pos= MIN(ofr[i]*color_ramp_len,color_ramp_len);
- }
- for(int j=at;j<pos;j++) {
- float t = (j-at)/float(pos-at);
- Color c = color_at.linear_interpolate(to,t);
- crw[j*4+0]=Math::fast_ftoi( CLAMP(c.r*255.0,0,255) );
- crw[j*4+1]=Math::fast_ftoi( CLAMP(c.g*255.0,0,255) );
- crw[j*4+2]=Math::fast_ftoi( CLAMP(c.b*255.0,0,255) );
- crw[j*4+3]=Math::fast_ftoi( CLAMP(c.a*255.0,0,255) );
- }
-
- at=pos;
- color_at=to;
- }
- }
-
- Image gradient(color_ramp_len,1,0,Image::FORMAT_RGBA8,cramp);
- Ref<ImageTexture> it = memnew( ImageTexture );
- it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
-
- String crampname= "cramp_"+itos(p_node->id);
- set_default_texture_param(crampname,it);
-
- code +="uniform texture "+crampname+";\n";
- code +="vec4 "+crampname+"_r=tex("+crampname+",vec2("+p_inputs[0]+",0));\n";
- code += OUTNAME(p_node->id,0)+"="+crampname+"_r.rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+crampname+"_r.a;\n";
-
- }break;
- case NODE_CURVE_MAP: {
- DEF_SCALAR(0);
- static const int curve_map_len=256;
- bool mapped[256];
- zeromem(mapped,sizeof(mapped));
- PoolVector<uint8_t> cmap;
- cmap.resize(curve_map_len);
- {
-
- PoolVector<Point2> points=p_node->param1;
- int pc =points.size();
- PoolVector<uint8_t>::Write cmw = cmap.write();
- PoolVector<Point2>::Read pr = points.read();
-
- Vector2 prev=Vector2(0,0);
- Vector2 prev2=Vector2(0,0);
-
- for(int i=-1;i<pc;i++) {
-
- Vector2 next;
- Vector2 next2;
- if (i+1>=pc) {
- next=Vector2(1,1);
- } else {
- next=Vector2(pr[i+1].x,pr[i+1].y);
- }
-
- if (i+2>=pc) {
- next2=Vector2(1,1);
- } else {
- next2=Vector2(pr[i+2].x,pr[i+2].y);
- }
-
- /*if (i==-1 && prev.offset==next.offset) {
- prev=next;
- continue;
- }*/
-
- _plot_curve(prev2,prev,next,next2,cmw.ptr(),mapped);
-
- prev2=prev;
- prev=next;
- }
-
- uint8_t pp=0;
- for(int i=0;i<curve_map_len;i++) {
-
- if (!mapped[i]) {
- cmw[i]=pp;
- } else {
- pp=cmw[i];
- }
- }
- }
-
-
-
- Image gradient(curve_map_len,1,0,Image::FORMAT_L8,cmap);
- Ref<ImageTexture> it = memnew( ImageTexture );
- it->create_from_image(gradient,Texture::FLAG_FILTER|Texture::FLAG_MIPMAPS);
-
- String cmapname= "cmap_"+itos(p_node->id);
- set_default_texture_param(cmapname,it);
-
- code +="uniform texture "+cmapname+";\n";
- code += OUTNAME(p_node->id,0)+"=tex("+cmapname+",vec2("+p_inputs[0]+",0)).r;\n";
-
- }break;
- case NODE_SCALAR_INPUT: {
- String name = p_node->param1;
- float dv=p_node->param2;
- code +="uniform float "+name+"="+rtos(dv)+";\n";
- code += OUTNAME(p_node->id,0)+"="+name+";\n";
- }break;
- case NODE_VEC_INPUT: {
-
- String name = p_node->param1;
- Vector3 dv=p_node->param2;
- code +="uniform vec3 "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
- code += OUTNAME(p_node->id,0)+"="+name+";\n";
- }break;
- case NODE_RGB_INPUT: {
-
- String name = p_node->param1;
- Color dv= p_node->param2;
-
- code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.b)+","+rtos(dv.a)+");\n";
- code += OUTNAME(p_node->id,0)+"="+name+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+name+".a;\n";
-
- }break;
- case NODE_XFORM_INPUT: {
-
- String name = p_node->param1;
- Transform dv= p_node->param2;
-
- code +="uniform mat4 "+name+"=mat4(\n";
- code+="\tvec4(vec3("+rtos(dv.basis.get_axis(0).x)+","+rtos(dv.basis.get_axis(0).y)+","+rtos(dv.basis.get_axis(0).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(dv.basis.get_axis(1).x)+","+rtos(dv.basis.get_axis(1).y)+","+rtos(dv.basis.get_axis(1).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(dv.basis.get_axis(2).x)+","+rtos(dv.basis.get_axis(2).y)+","+rtos(dv.basis.get_axis(2).z)+"),0),\n";
- code+="\tvec4(vec3("+rtos(dv.origin.x)+","+rtos(dv.origin.y)+","+rtos(dv.origin.z)+"),1)\n";
- code+=");";
-
- code += OUTNAME(p_node->id,0)+"="+name+";\n";
-
- }break;
- case NODE_TEXTURE_INPUT: {
- DEF_VEC(0);
- String name = p_node->param1;
- String rname="rt_read_tex"+itos(p_node->id);
- code +="uniform texture "+name+";";
- code +="vec4 "+rname+"=tex("+name+","+p_inputs[0]+".xy);\n";
- code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
-
- }break;
- case NODE_CUBEMAP_INPUT: {
- DEF_VEC(0);
- String name = p_node->param1;
- code +="uniform cubemap "+name+";";
- String rname="rt_read_tex"+itos(p_node->id);
- code +="vec4 "+rname+"=texcube("+name+","+p_inputs[0]+".xy);\n";
- code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
- }break;
- case NODE_DEFAULT_TEXTURE: {
- DEF_VEC(0);
-
- if (get_mode()==MODE_CANVAS_ITEM && p_type==SHADER_TYPE_FRAGMENT) {
-
- String rname="rt_default_tex"+itos(p_node->id);
- code +="vec4 "+rname+"=tex(TEXTURE,"+p_inputs[0]+".xy);\n";
- code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
- code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
-
- } else {
- //not supported
- code += OUTNAME(p_node->id,0)+"=vec3(0,0,0);\n";
- code += OUTNAME(p_node->id,1)+"=1.0;\n";
-
- }
- } break;
- case NODE_OUTPUT: {
-
-
- }break;
- case NODE_COMMENT: {
-
- }break;
- case NODE_TYPE_MAX: {
-
- }
- }
-#undef DEF_SCALAR
-#undef DEF_COLOR
-#undef DEF_MATRIX
-#undef DEF_VEC
-}
-
-#endif
diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h
deleted file mode 100644
index e3a68f8572..0000000000
--- a/scene/resources/shader_graph.h
+++ /dev/null
@@ -1,446 +0,0 @@
-/*************************************************************************/
-/* shader_graph.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. */
-/*************************************************************************/
-
-#ifndef SHADER_GRAPH_H
-#define SHADER_GRAPH_H
-
-// FIXME: Needs to be ported to the new 3.0 shader API
-#if 0
-#include "map.h"
-#include "scene/resources/shader.h"
-
-class ShaderGraph : public Shader {
-
- GDCLASS( ShaderGraph, Shader );
- RES_BASE_EXTENSION("vshader");
-
-public:
-
- enum NodeType {
- NODE_INPUT, // all inputs (shader type dependent)
- NODE_SCALAR_CONST, //scalar constant
- NODE_VEC_CONST, //vec3 constant
- NODE_RGB_CONST, //rgb constant (shows a color picker instead)
- NODE_XFORM_CONST, // 4x4 matrix constant
- NODE_TIME, // time in seconds
- NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader)
- NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc)
- NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc)
- NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc)
- NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc.
- NODE_XFORM_MULT, // mat4 x mat4
- NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option)
- NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option)
- NODE_SCALAR_FUNC, // scalar function (sin, cos, etc)
- NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc)
- NODE_VEC_LEN, // vec3 length
- NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output)
- NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs
- NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output
- NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output
- NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
- NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
- NODE_VEC_INTERP, // vec3 interpolation (with optional curve)
- NODE_COLOR_RAMP, //take scalar, output vec3
- NODE_CURVE_MAP, //take scalar, otput scalar
- NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
- NODE_VEC_INPUT, // vec3 uniform (assignable in material)
- NODE_RGB_INPUT, // color uniform (assignable in material)
- NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
- NODE_TEXTURE_INPUT, // texture input (assignable in material)
- NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
- NODE_DEFAULT_TEXTURE,
- NODE_OUTPUT, // output (shader type dependent)
- NODE_COMMENT, // comment
- NODE_TYPE_MAX
- };
-
-
- struct Connection {
-
- int src_id;
- int src_slot;
- int dst_id;
- int dst_slot;
- };
-
- enum SlotType {
-
- SLOT_TYPE_SCALAR,
- SLOT_TYPE_VEC,
- SLOT_TYPE_XFORM,
- SLOT_TYPE_TEXTURE,
- SLOT_MAX
- };
-
- enum ShaderType {
- SHADER_TYPE_VERTEX,
- SHADER_TYPE_FRAGMENT,
- SHADER_TYPE_LIGHT,
- SHADER_TYPE_MAX
- };
-
- enum SlotDir {
- SLOT_IN,
- SLOT_OUT
- };
-
- enum GraphError {
- GRAPH_OK,
- GRAPH_ERROR_CYCLIC,
- GRAPH_ERROR_MISSING_CONNECTIONS
- };
-
-private:
-
- String _find_unique_name(const String& p_base);
-
- enum {SLOT_DEFAULT_VALUE = 0x7FFFFFFF};
- struct SourceSlot {
-
- int id;
- int slot;
- bool operator==(const SourceSlot& p_slot) const {
- return id==p_slot.id && slot==p_slot.slot;
- }
- };
-
- struct Node {
-
- Vector2 pos;
- NodeType type;
- Variant param1;
- Variant param2;
- Map<int, Variant> defaults;
- int id;
- mutable int order; // used for sorting
- int sort_order;
- Map<int,SourceSlot> connections;
-
- };
-
- struct ShaderData {
- Map<int,Node> node_map;
- GraphError error;
- } shader[3];
-
-
-
- struct InOutParamInfo {
- Mode shader_mode;
- ShaderType shader_type;
- const char *name;
- const char *variable;
- const char *postfix;
- SlotType slot_type;
- SlotDir dir;
- };
-
- static const InOutParamInfo inout_param_info[];
-
- struct NodeSlotInfo {
-
- enum { MAX_INS=3, MAX_OUTS=3 };
- NodeType type;
- const SlotType ins[MAX_INS];
- const SlotType outs[MAX_OUTS];
- };
-
- static const NodeSlotInfo node_slot_info[];
-
- bool _pending_update_shader;
- void _update_shader();
- void _request_update();
-
- void _plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector2& p_c,const Vector2& p_d,uint8_t* p_heights,bool *p_useds);
- void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code);
-
- Array _get_node_list(ShaderType p_type) const;
- Array _get_connections(ShaderType p_type) const;
-
- void _set_data(const Dictionary& p_data);
- Dictionary _get_data() const;
-protected:
-
- static void _bind_methods();
-
-public:
-
-
- void node_add(ShaderType p_type, NodeType p_node_type, int p_id);
- void node_remove(ShaderType p_which,int p_id);
- void node_set_position(ShaderType p_which,int p_id,const Point2& p_pos);
- Point2 node_get_position(ShaderType p_which,int p_id) const;
-
- void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
- NodeType node_get_type(ShaderType p_which,int p_id) const;
-
- void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value);
- float scalar_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
- Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
- Color rgb_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
- Transform xform_const_node_get_value(ShaderType p_which,int p_id) const;
-
- void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size);
- int texture_node_get_filter_size(ShaderType p_which,int p_id) const;
-
- void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
- float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
-
- void duplicate_nodes(ShaderType p_which, List<int> &p_nodes);
-
- List<int> generate_ids(ShaderType p_type, int count);
-
- enum ScalarOp {
- SCALAR_OP_ADD,
- SCALAR_OP_SUB,
- SCALAR_OP_MUL,
- SCALAR_OP_DIV,
- SCALAR_OP_MOD,
- SCALAR_OP_POW,
- SCALAR_OP_MAX,
- SCALAR_OP_MIN,
- SCALAR_OP_ATAN2,
- SCALAR_MAX_OP
- };
-
- void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op);
- ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const;
-
- enum VecOp {
- VEC_OP_ADD,
- VEC_OP_SUB,
- VEC_OP_MUL,
- VEC_OP_DIV,
- VEC_OP_MOD,
- VEC_OP_POW,
- VEC_OP_MAX,
- VEC_OP_MIN,
- VEC_OP_CROSS,
- VEC_MAX_OP
- };
-
- void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op);
- VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const;
-
- enum VecScalarOp {
- VEC_SCALAR_OP_MUL,
- VEC_SCALAR_OP_DIV,
- VEC_SCALAR_OP_POW,
- VEC_SCALAR_MAX_OP
- };
-
- void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op);
- VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const;
-
- enum RGBOp {
- RGB_OP_SCREEN,
- RGB_OP_DIFFERENCE,
- RGB_OP_DARKEN,
- RGB_OP_LIGHTEN,
- RGB_OP_OVERLAY,
- RGB_OP_DODGE,
- RGB_OP_BURN,
- RGB_OP_SOFT_LIGHT,
- RGB_OP_HARD_LIGHT,
- RGB_MAX_OP
- };
-
- void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op);
- RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const;
-
- void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation);
- bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const;
-
- enum ScalarFunc {
- SCALAR_FUNC_SIN,
- SCALAR_FUNC_COS,
- SCALAR_FUNC_TAN,
- SCALAR_FUNC_ASIN,
- SCALAR_FUNC_ACOS,
- SCALAR_FUNC_ATAN,
- SCALAR_FUNC_SINH,
- SCALAR_FUNC_COSH,
- SCALAR_FUNC_TANH,
- SCALAR_FUNC_LOG,
- SCALAR_FUNC_EXP,
- SCALAR_FUNC_SQRT,
- SCALAR_FUNC_ABS,
- SCALAR_FUNC_SIGN,
- SCALAR_FUNC_FLOOR,
- SCALAR_FUNC_ROUND,
- SCALAR_FUNC_CEIL,
- SCALAR_FUNC_FRAC,
- SCALAR_FUNC_SATURATE,
- SCALAR_FUNC_NEGATE,
- SCALAR_MAX_FUNC
- };
-
- void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func);
- ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const;
-
- enum VecFunc {
- VEC_FUNC_NORMALIZE,
- VEC_FUNC_SATURATE,
- VEC_FUNC_NEGATE,
- VEC_FUNC_RECIPROCAL,
- VEC_FUNC_RGB2HSV,
- VEC_FUNC_HSV2RGB,
- VEC_MAX_FUNC
- };
-
- void default_set_value(ShaderType p_which,int p_id,int p_param, const Variant& p_value);
- Variant default_get_value(ShaderType p_which,int p_id,int p_param);
-
- void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
- VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
-
- void color_ramp_node_set_ramp(ShaderType p_which,int p_id,const PoolVector<Color>& p_colors, const PoolVector<real_t>& p_offsets);
- PoolVector<Color> color_ramp_node_get_colors(ShaderType p_which,int p_id) const;
- PoolVector<real_t> color_ramp_node_get_offsets(ShaderType p_which,int p_id) const;
-
- void curve_map_node_set_points(ShaderType p_which, int p_id, const PoolVector<Vector2>& p_points);
- PoolVector<Vector2> curve_map_node_get_points(ShaderType p_which,int p_id) const;
-
- void input_node_set_name(ShaderType p_which,int p_id,const String& p_name);
- String input_node_get_name(ShaderType p_which,int p_id);
-
- void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value);
- float scalar_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
- Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
- Color rgb_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
- Transform xform_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref<Texture>& p_texture);
- Ref<Texture> texture_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref<CubeMap>& p_cubemap);
- Ref<CubeMap> cubemap_input_node_get_value(ShaderType p_which,int p_id) const;
-
- void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment);
- String comment_node_get_text(ShaderType p_which,int p_id) const;
-
- Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
- bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
- void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
-
- void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
-
- bool is_slot_connected(ShaderType p_which,int p_dst_id,int slot_id);
-
- void clear(ShaderType p_which);
-
- Variant node_get_state(ShaderType p_type, int p_node) const;
- void node_set_state(ShaderType p_type, int p_id, const Variant& p_state);
-
- GraphError get_graph_error(ShaderType p_type) const;
-
- int node_count(ShaderType p_which, int p_type);
-
- static int get_type_input_count(NodeType p_type);
- static int get_type_output_count(NodeType p_type);
- static SlotType get_type_input_type(NodeType p_type,int p_idx);
- static SlotType get_type_output_type(NodeType p_type,int p_idx);
- static bool is_type_valid(Mode p_mode,ShaderType p_type);
-
-
- struct SlotInfo {
- String name;
- SlotType type;
- SlotDir dir;
- };
-
- static void get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots);
-
- static int get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
- static int get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type);
- static SlotType get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
- static SlotType get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx);
-
-
- ShaderGraph(Mode p_mode);
- ~ShaderGraph();
-};
-
-//helper functions
-
-
-
-
-VARIANT_ENUM_CAST( ShaderGraph::NodeType );
-VARIANT_ENUM_CAST( ShaderGraph::ShaderType );
-VARIANT_ENUM_CAST( ShaderGraph::SlotType );
-VARIANT_ENUM_CAST( ShaderGraph::ScalarOp );
-VARIANT_ENUM_CAST( ShaderGraph::VecOp );
-VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
-VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
-VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
-VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
-VARIANT_ENUM_CAST( ShaderGraph::GraphError );
-
-
-class MaterialShaderGraph : public ShaderGraph {
-
- GDCLASS( MaterialShaderGraph, ShaderGraph );
-
-public:
-
-
- MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) {
-
- }
-};
-
-class CanvasItemShaderGraph : public ShaderGraph {
-
- GDCLASS( CanvasItemShaderGraph, ShaderGraph );
-
-public:
-
-
- CanvasItemShaderGraph() : ShaderGraph(MODE_CANVAS_ITEM) {
-
- }
-};
-
-#endif
-#endif // SHADER_GRAPH_H
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 418d8ce819..a48ce0564b 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -50,6 +50,15 @@ void Shape::add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p
}
}
+real_t Shape::get_margin() const {
+ return margin;
+}
+
+void Shape::set_margin(real_t p_margin) {
+ margin = p_margin;
+ PhysicsServer::get_singleton()->shape_set_margin(shape, margin);
+}
+
Ref<ArrayMesh> Shape::get_debug_mesh() {
if (debug_mesh_cache.is_valid())
@@ -87,12 +96,22 @@ Ref<ArrayMesh> Shape::get_debug_mesh() {
return debug_mesh_cache;
}
-Shape::Shape() {
+void Shape::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape::set_margin);
+ ClassDB::bind_method(D_METHOD("get_margin"), &Shape::get_margin);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0.04,10,0.01"), "set_margin", "get_margin");
+}
+
+Shape::Shape() :
+ margin(0.04) {
ERR_PRINT("Constructor must not be called!");
}
-Shape::Shape(RID p_shape) {
+Shape::Shape(RID p_shape) :
+ margin(0.04) {
shape = p_shape;
}
diff --git a/scene/resources/shape.h b/scene/resources/shape.h
index ad87a69679..0c44b86e92 100644
--- a/scene/resources/shape.h
+++ b/scene/resources/shape.h
@@ -40,10 +40,13 @@ class Shape : public Resource {
OBJ_SAVE_TYPE(Shape);
RES_BASE_EXTENSION("shape");
RID shape;
+ real_t margin;
Ref<ArrayMesh> debug_mesh_cache;
protected:
+ static void _bind_methods();
+
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape(RID p_shape);
@@ -55,6 +58,9 @@ public:
void add_vertices_to_array(PoolVector<Vector3> &array, const Transform &p_xform);
+ real_t get_margin() const;
+ void set_margin(real_t p_margin);
+
Shape();
~Shape();
};
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index ec489e5c5b..81fabf40fe 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -755,15 +755,11 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
for (List<int>::Element *E = nindices.front(); E; E = E->next()) {
int dst_index = E->get() + vfrom;
- /*
- if (dst_index <0 || dst_index>=vertex_array.size()) {
- print_line("invalid index!");
- }
- */
index_array.push_back(dst_index);
}
- if (index_array.size() % 3)
- print_line("IA not div of 3?");
+ if (index_array.size() % 3) {
+ WARN_PRINT("SurfaceTool: Index array not a multiple of 3.");
+ }
}
//mikktspace callbacks
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 60a99d255a..811e5c3d2c 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "texture.h"
+#include "bit_mask.h"
#include "core/method_bind_ext.gen.inc"
#include "core/os/os.h"
#include "core_string_names.h"
@@ -39,6 +40,9 @@ Size2 Texture::get_size() const {
return Size2(get_width(), get_height());
}
+bool Texture::is_pixel_opaque(int p_x, int p_y) const {
+ return true;
+}
void Texture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
@@ -234,6 +238,7 @@ void ImageTexture::set_data(const Ref<Image> &p_image) {
VisualServer::get_singleton()->texture_set_data(texture, p_image);
_change_notify();
+ alpha_cache.unref();
}
void ImageTexture::_resource_path_changed() {
@@ -288,6 +293,41 @@ void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, p_clip_uv);
}
+bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_data();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+ alpha_cache.instance();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / w;
+ int y = p_y * ah / h;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, aw);
+
+ return alpha_cache->get_bit(Point2(x, y));
+ }
+
+ return true;
+}
+
void ImageTexture::set_size_override(const Size2 &p_size) {
Size2 s = p_size;
@@ -421,6 +461,8 @@ Image::Format StreamTexture::get_format() const {
Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &flags, Ref<Image> &image, int p_size_limit) {
+ alpha_cache.unref();
+
ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
@@ -438,7 +480,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla
flags = f->get_32(); //texture flags!
uint32_t df = f->get_32(); //data format
-/*
+ /*
print_line("width: " + itos(tw));
print_line("height: " + itos(th));
print_line("flags: " + itos(flags));
@@ -709,6 +751,40 @@ Ref<Image> StreamTexture::get_data() const {
return VS::get_singleton()->texture_get_data(texture);
}
+bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ if (!alpha_cache.is_valid()) {
+ Ref<Image> img = get_data();
+ if (img.is_valid()) {
+ if (img->is_compressed()) { //must decompress, if compressed
+ Ref<Image> decom = img->duplicate();
+ decom->decompress();
+ img = decom;
+ }
+ alpha_cache.instance();
+ alpha_cache->create_from_image_alpha(img);
+ }
+ }
+
+ if (alpha_cache.is_valid()) {
+
+ int aw = int(alpha_cache->get_size().width);
+ int ah = int(alpha_cache->get_size().height);
+ if (aw == 0 || ah == 0) {
+ return true;
+ }
+
+ int x = p_x * aw / w;
+ int y = p_y * ah / h;
+
+ x = CLAMP(x, 0, aw);
+ y = CLAMP(y, 0, aw);
+
+ return alpha_cache->get_bit(Point2(x, y));
+ }
+
+ return true;
+}
void StreamTexture::set_flags(uint32_t p_flags) {
flags = p_flags;
VS::get_singleton()->texture_set_flags(texture, flags);
@@ -993,6 +1069,15 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
return true;
}
+bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ if (atlas.is_valid()) {
+ return atlas->is_pixel_opaque(p_x + region.position.x + margin.position.x, p_x + region.position.y + margin.position.y);
+ }
+
+ return true;
+}
+
AtlasTexture::AtlasTexture() {
filter_clip = false;
}
@@ -1170,6 +1255,23 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
}
}
+bool LargeTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ for (int i = 0; i < pieces.size(); i++) {
+
+ // TODO
+ if (!pieces[i].texture.is_valid())
+ continue;
+
+ Rect2 rect(pieces[i].offset, pieces[i].texture->get_size());
+ if (rect.has_point(Point2(p_x, p_y))) {
+ return pieces[i].texture->is_pixel_opaque(p_x - rect.position.x, p_y - rect.position.y);
+ }
+ }
+
+ return true;
+}
+
LargeTexture::LargeTexture() {
}
@@ -1652,7 +1754,7 @@ ProxyTexture::~ProxyTexture() {
void AnimatedTexture::_update_proxy() {
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
float delta;
if (prev_ticks == 0) {
@@ -1698,7 +1800,7 @@ void AnimatedTexture::_update_proxy() {
void AnimatedTexture::set_frames(int p_frames) {
ERR_FAIL_COND(p_frames < 1 || p_frames > MAX_FRAMES);
- _THREAD_SAFE_METHOD_
+ RWLockWrite r(rw_lock);
frame_count = p_frames;
}
@@ -1709,14 +1811,14 @@ int AnimatedTexture::get_frames() const {
void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture> &p_texture) {
ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
- _THREAD_SAFE_METHOD_
+ RWLockWrite w(rw_lock);
frames[p_frame].texture = p_texture;
}
Ref<Texture> AnimatedTexture::get_frame_texture(int p_frame) const {
ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, Ref<Texture>());
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
return frames[p_frame].texture;
}
@@ -1724,14 +1826,14 @@ Ref<Texture> AnimatedTexture::get_frame_texture(int p_frame) const {
void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) {
ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
frames[p_frame].delay_sec = p_delay_sec;
}
float AnimatedTexture::get_frame_delay(int p_frame) const {
ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
return frames[p_frame].delay_sec;
}
@@ -1746,8 +1848,7 @@ float AnimatedTexture::get_fps() const {
}
int AnimatedTexture::get_width() const {
-
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return 1;
@@ -1756,8 +1857,7 @@ int AnimatedTexture::get_width() const {
return frames[current_frame].texture->get_width();
}
int AnimatedTexture::get_height() const {
-
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return 1;
@@ -1771,7 +1871,7 @@ RID AnimatedTexture::get_rid() const {
bool AnimatedTexture::has_alpha() const {
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return false;
@@ -1782,7 +1882,7 @@ bool AnimatedTexture::has_alpha() const {
Ref<Image> AnimatedTexture::get_data() const {
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return Ref<Image>();
@@ -1791,11 +1891,21 @@ Ref<Image> AnimatedTexture::get_data() const {
return frames[current_frame].texture->get_data();
}
+bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
+
+ RWLockRead r(rw_lock);
+
+ if (frames[current_frame].texture.is_valid()) {
+ return frames[current_frame].texture->is_pixel_opaque(p_x, p_y);
+ }
+ return true;
+}
+
void AnimatedTexture::set_flags(uint32_t p_flags) {
}
uint32_t AnimatedTexture::get_flags() const {
- _THREAD_SAFE_METHOD_
+ RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return 0;
@@ -1848,10 +1958,19 @@ AnimatedTexture::AnimatedTexture() {
prev_ticks = 0;
current_frame = 0;
VisualServer::get_singleton()->connect("frame_pre_draw", this, "_update_proxy");
+
+#ifndef NO_THREADS
+ rw_lock = RWLock::create();
+#else
+ rw_lock = NULL;
+#endif
}
AnimatedTexture::~AnimatedTexture() {
VS::get_singleton()->free(proxy);
+ if (rw_lock) {
+ memdelete(rw_lock);
+ }
}
///////////////////////////////
@@ -1976,7 +2095,7 @@ void TextureLayered::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &TextureLayered::create, DEFVAL(FLAGS_DEFAULT));
ClassDB::bind_method(D_METHOD("set_layer_data", "image", "layer"), &TextureLayered::set_layer_data);
- ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::set_layer_data);
+ ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::get_layer_data);
ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &TextureLayered::set_data_partial, DEFVAL(0));
ClassDB::bind_method(D_METHOD("_set_data", "data"), &TextureLayered::_set_data);
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index c1331fb3fe..79e6d2cdf9 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -34,6 +34,7 @@
#include "curve.h"
#include "io/resource_loader.h"
#include "os/mutex.h"
+#include "os/rw_lock.h"
#include "os/thread_safe.h"
#include "rect2.h"
#include "resource.h"
@@ -67,6 +68,8 @@ public:
virtual Size2 get_size() const;
virtual RID get_rid() const = 0;
+ virtual bool is_pixel_opaque(int p_x, int p_y) const;
+
virtual bool has_alpha() const = 0;
virtual void set_flags(uint32_t p_flags) = 0;
@@ -84,6 +87,8 @@ public:
VARIANT_ENUM_CAST(Texture::Flags);
+class BitMap;
+
class ImageTexture : public Texture {
GDCLASS(ImageTexture, Texture);
@@ -104,6 +109,7 @@ private:
Storage storage;
Size2 size_override;
float lossy_storage_quality;
+ mutable Ref<BitMap> alpha_cache;
protected:
virtual void reload_from_file();
@@ -143,6 +149,8 @@ public:
void set_storage(Storage p_storage);
Storage get_storage() const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
void set_lossy_storage_quality(float p_lossy_storage_quality);
float get_lossy_storage_quality() const;
@@ -183,6 +191,7 @@ private:
Image::Format format;
uint32_t flags;
int w, h;
+ mutable Ref<BitMap> alpha_cache;
virtual void reload_from_file();
@@ -215,6 +224,7 @@ public:
virtual bool has_alpha() const;
virtual void set_flags(uint32_t p_flags);
+ bool is_pixel_opaque(int p_x, int p_y) const;
virtual Ref<Image> get_data() const;
@@ -272,6 +282,8 @@ public:
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
AtlasTexture();
};
@@ -319,6 +331,8 @@ public:
virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
LargeTexture();
};
@@ -609,7 +623,8 @@ public:
class AnimatedTexture : public Texture {
GDCLASS(AnimatedTexture, Texture)
- _THREAD_SAFE_CLASS_
+ //use readers writers lock for this, since its far more times read than written to
+ RWLock *rw_lock;
private:
enum {
@@ -668,6 +683,8 @@ public:
virtual Ref<Image> get_data() const;
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
AnimatedTexture();
~AnimatedTexture();
};
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index d8fc3677fb..dac12205b6 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -431,7 +431,6 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
global_code += "\n\n";
String final_code = global_code;
final_code += code;
- //print_line(final_code);
return final_code;
}
@@ -914,7 +913,6 @@ void VisualShader::_update_shader() const {
String final_code = global_code;
final_code += code;
const_cast<VisualShader *>(this)->set_code(final_code);
- //print_line(final_code);
for (int i = 0; i < default_tex_params.size(); i++) {
const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param);
}
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 661606c7ef..e468b3dab4 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -201,4 +201,6 @@ SceneStringNames::SceneStringNames() {
}
_mesh_changed = StaticCString::create("_mesh_changed");
+
+ parameters_base_path = "parameters/";
}
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 817158f9f3..dbbcf79b9f 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -203,6 +203,8 @@ public:
StringName output;
+ StringName parameters_base_path;
+
enum {
MAX_MATERIALS = 32
};