diff options
Diffstat (limited to 'scene')
85 files changed, 2670 insertions, 4341 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/particles_2d.cpp b/scene/2d/particles_2d.cpp index 1da1d44b17..a4c3057416 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -74,14 +74,14 @@ void Particles2D::set_randomness_ratio(float p_ratio) { randomness_ratio = p_ratio; VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio); } -void Particles2D::set_visibility_rect(const Rect2 &p_aabb) { +void Particles2D::set_visibility_rect(const Rect2 &p_visibility_rect) { - visibility_rect = p_aabb; + visibility_rect = p_visibility_rect; AABB aabb; - aabb.position.x = p_aabb.position.x; - aabb.position.y = p_aabb.position.y; - aabb.size.x = p_aabb.size.x; - aabb.size.y = p_aabb.size.y; + aabb.position.x = p_visibility_rect.position.x; + aabb.position.y = p_visibility_rect.position.y; + aabb.size.x = p_visibility_rect.size.x; + aabb.size.y = p_visibility_rect.size.y; VS::get_singleton()->particles_set_custom_aabb(particles, aabb); @@ -326,7 +326,7 @@ void Particles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time); ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio); - ClassDB::bind_method(D_METHOD("set_visibility_rect", "aabb"), &Particles2D::set_visibility_rect); + ClassDB::bind_method(D_METHOD("set_visibility_rect", "visibility_rect"), &Particles2D::set_visibility_rect); ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates); ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps); ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta); @@ -372,13 +372,13 @@ void Particles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_GROUP("Drawing", ""); - ADD_PROPERTY(PropertyInfo(Variant::AABB, "visibility_rect"), "set_visibility_rect", "get_visibility_rect"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); ADD_GROUP("Process Material", "process_"); diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index f367095581..31a66afb2a 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -84,7 +84,7 @@ public: void set_pre_process_time(float p_time); void set_explosiveness_ratio(float p_ratio); void set_randomness_ratio(float p_ratio); - void set_visibility_rect(const Rect2 &p_aabb); + void set_visibility_rect(const Rect2 &p_visibility_rect); void set_use_local_coordinates(bool p_enable); void set_process_material(const Ref<Material> &p_material); void set_speed_scale(float p_scale); 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..fa14174089 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]; @@ -1190,7 +1188,7 @@ void CPUParticles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); 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/particles.cpp b/scene/3d/particles.cpp index 4900692155..6ba569ac75 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -329,7 +329,7 @@ void Particles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); 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/physics_joint.cpp b/scene/3d/physics_joint.cpp index 7988c43eab..a30fc0ac3e 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -48,18 +48,14 @@ void Joint::_update_joint(bool p_only_free) { Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; - if (!node_a || !node_b) - return; - PhysicsBody *body_a = Object::cast_to<PhysicsBody>(node_a); PhysicsBody *body_b = Object::cast_to<PhysicsBody>(node_b); - if (!body_a || !body_b) - return; - - if (!body_a) { + if (!body_a && body_b) SWAP(body_a, body_b); - } + + if (!body_a) + return; joint = _configure_joint(body_a, body_b); @@ -69,7 +65,8 @@ void Joint::_update_joint(bool p_only_free) { PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority); ba = body_a->get_rid(); - bb = body_b->get_rid(); + if (body_b) + bb = body_b->get_rid(); PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } 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..73bd00e456 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()) { @@ -718,6 +698,28 @@ void AnimationTree::_process_graph(float p_delta) { AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); + ObjectID current_animation_player = 0; + + if (player) { + current_animation_player = player->get_instance_id(); + } + + if (last_animation_player != current_animation_player) { + + if (last_animation_player) { + Object *old_player = ObjectDB::get_instance(last_animation_player); + if (old_player) { + old_player->disconnect("caches_cleared", this, "_clear_caches"); + } + } + + if (player) { + player->connect("caches_cleared", this, "_clear_caches"); + } + + last_animation_player = current_animation_player; + } + if (!player) { ERR_PRINT("AnimationTree: path points to a node not an AnimationPlayer, disabling playback"); set_active(false); @@ -741,6 +743,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 +760,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) { @@ -1216,6 +1219,13 @@ void AnimationTree::_notification(int p_what) { if (p_what == NOTIFICATION_EXIT_TREE) { _clear_caches(); + if (last_animation_player) { + + Object *old_player = ObjectDB::get_instance(last_animation_player); + if (old_player) { + old_player->disconnect("caches_cleared", this, "_clear_caches"); + } + } } } @@ -1297,6 +1307,148 @@ 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 +1467,17 @@ 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); + ClassDB::bind_method(D_METHOD("_clear_caches"), &AnimationTree::_clear_caches); - 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 +1496,9 @@ AnimationTree::AnimationTree() { cache_valid = false; setup_pass = 1; started = true; + properties_dirty = true; + last_animation_player = 0; } 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..6cb363d50a 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,31 @@ 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); + + ObjectID last_animation_player; + 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 +299,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..69975e6195 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) { @@ -52,9 +54,9 @@ FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child( } /// Build a chain that starts from the root to tip -void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { +bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { - ERR_FAIL_COND(-1 == p_task->root_bone); + ERR_FAIL_COND_V(-1 == p_task->root_bone, false); Chain &chain(p_task->chain); @@ -75,8 +77,8 @@ void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) { const EndEffector *ee(&p_task->end_effectors[x]); - ERR_FAIL_COND(p_task->root_bone >= ee->tip_bone); - ERR_FAIL_INDEX(ee->tip_bone, p_task->skeleton->get_bone_count()); + ERR_FAIL_COND_V(p_task->root_bone >= ee->tip_bone, false); + ERR_FAIL_INDEX_V(ee->tip_bone, p_task->skeleton->get_bone_count(), false); sub_chain_size = 0; // Picks all IDs that composing a single chain in reverse order (except the root) @@ -131,6 +133,7 @@ void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain break; } } + return true; } void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_chain_item) { @@ -245,7 +248,10 @@ FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleto task->end_effectors.push_back(ee); task->goal_global_transform = goal_transform; - build_chain(task); + if (!build_chain(task)) { + free_task(task); + return NULL; + } return task; } @@ -533,8 +539,10 @@ void SkeletonIK::reload_chain() { return; task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform()); - task->max_iterations = max_iterations; - task->min_distance = min_distance; + if (task) { + task->max_iterations = max_iterations; + task->min_distance = min_distance; + } } void SkeletonIK::reload_goal() { @@ -549,3 +557,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..202d6959bb 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 */ @@ -121,7 +123,7 @@ public: private: /// Init a chain that starts from the root to tip - static void build_chain(Task *p_task, bool p_force_simple_chain = true); + static bool build_chain(Task *p_task, bool p_force_simple_chain = true); static void update_chain(const Skeleton *p_sk, ChainItem *p_chain_item); @@ -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..9bddaa7d29 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -284,7 +284,13 @@ bool FileDialog::_is_open_should_be_disabled() { if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE) return false; - TreeItem *ti = tree->get_selected(); + TreeItem *ti = tree->get_next_selected(tree->get_root()); + while (ti) { + TreeItem *prev_ti = ti; + ti = tree->get_next_selected(tree->get_root()); + if (ti == prev_ti) + break; + } // We have something that we can't select? if (!ti) return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder. @@ -328,6 +334,10 @@ void FileDialog::deselect_items() { } } +void FileDialog::_tree_multi_selected(Object *p_object, int p_cell, bool p_selected) { + _tree_selected(); +} + void FileDialog::_tree_selected() { TreeItem *ti = tree->get_selected(); @@ -582,7 +592,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) { @@ -753,6 +764,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_unhandled_input"), &FileDialog::_unhandled_input); + ClassDB::bind_method(D_METHOD("_tree_multi_selected"), &FileDialog::_tree_multi_selected); ClassDB::bind_method(D_METHOD("_tree_selected"), &FileDialog::_tree_selected); ClassDB::bind_method(D_METHOD("_tree_item_activated"), &FileDialog::_tree_item_activated); ClassDB::bind_method(D_METHOD("_dir_entered"), &FileDialog::_dir_entered); @@ -793,7 +805,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_mode", "get_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "filters"), "set_filters", "get_filters"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); @@ -889,6 +901,7 @@ FileDialog::FileDialog() { _update_drives(); connect("confirmed", this, "_action_pressed"); + tree->connect("multi_selected", this, "_tree_multi_selected", varray(), CONNECT_DEFERRED); tree->connect("cell_selected", this, "_tree_selected", varray(), CONNECT_DEFERRED); tree->connect("item_activated", this, "_tree_item_activated", varray()); tree->connect("nothing_selected", this, "deselect_items"); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index ad483d5dab..3227f1c3a8 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -104,6 +104,7 @@ private: void update_file_list(); void update_filters(); + void _tree_multi_selected(Object *p_object, int p_cell, bool p_selected); void _tree_selected(); void _select_drive(int p_idx); 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 d61bd97c2a..9f5c12e87f 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -502,7 +502,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { bool selected = !items[j].selected; select(j, false); if (selected) - emit_signal("multi_selected", i, true); + emit_signal("multi_selected", j, true); } if (mb->get_button_index() == BUTTON_RIGHT) { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 549daecdae..1f3d5e6e13 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -866,15 +866,14 @@ void LineEdit::_notification(int p_what) { void LineEdit::copy_text() { - if (selection.enabled) { - + if (selection.enabled && !pass) { OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin)); } } void LineEdit::cut_text() { - if (selection.enabled) { + if (selection.enabled && !pass) { OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin)); selection_delete(); } 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..ec98b01ced 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -5640,6 +5640,10 @@ void TextEdit::_confirm_completion() { end_complex_operation(); _cancel_completion(); + + if (last_completion_char == '(') { + query_code_comple(); + } } void TextEdit::_cancel_code_hint() { @@ -5692,15 +5696,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 +5714,6 @@ void TextEdit::_update_completion_candidates() { } pre_keyword = keywords.has(kw); - //print_line("KW "+kw+"? "+itos(pre_keyword)); } else { @@ -5755,43 +5755,23 @@ void TextEdit::_update_completion_candidates() { completion_strings.write[i] = completion_strings[i].unquote().quote("'"); } - if (s == completion_strings[i]) { - // A perfect match, stop completion - _cancel_completion(); - return; + if (completion_strings[i].begins_with(s)) { + completion_options.push_back(completion_strings[i]); } + } - if (s.is_subsequence_ofi(completion_strings[i])) { - // don't remove duplicates if no input is provided - if (s != "" && completion_options.find(completion_strings[i]) != -1) { - continue; - } - // Calculate the similarity to keep completions in good order - float similarity; - if (completion_strings[i].begins_with(s)) { - // Substrings (same case) are the best candidates - similarity = 1.2; - } else if (completion_strings[i].to_lower().begins_with(s.to_lower())) { - // then any substrings - similarity = 1.1; - } else { - // Otherwise compute the similarity - similarity = s.to_lower().similarity(completion_strings[i].to_lower()); + if (completion_options.size() == 0) { + for (int i = 0; i < completion_strings.size(); i++) { + if (s.is_subsequence_of(completion_strings[i])) { + completion_options.push_back(completion_strings[i]); } + } + } - int comp_size = completion_options.size(); - if (comp_size == 0) { + if (completion_options.size() == 0) { + for (int i = 0; i < completion_strings.size(); i++) { + if (s.is_subsequence_ofi(completion_strings[i])) { completion_options.push_back(completion_strings[i]); - sim_cache.push_back(similarity); - } else { - float comp_sim; - int pos = 0; - do { - comp_sim = sim_cache[pos++]; - } while (pos < comp_size && similarity < comp_sim); - pos = similarity > comp_sim ? pos - 1 : pos; // Pos will be off by one - completion_options.insert(pos, completion_strings[i]); - sim_cache.insert(pos, similarity); } } } @@ -5799,7 +5779,12 @@ void TextEdit::_update_completion_candidates() { if (completion_options.size() == 0) { //no options to complete, cancel _cancel_completion(); + return; + } + if (completion_options.size() == 1 && s == completion_options[0]) { + // A perfect match, stop completion + _cancel_completion(); return; } diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 6e4fe88dbf..ff90576c1b 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -266,6 +266,8 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F } } + p_texture->get_rect_region(dst_rect, src_rect, dst_rect, src_rect); + RID ci = get_canvas_item(); VS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright, VS::NINE_PATCH_STRETCH, VS::NINE_PATCH_STRETCH, true, p_modulate); } 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..dccdd244ef 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>(); @@ -558,6 +563,9 @@ void register_scene_types() { /* REGISTER RESOURCES */ ClassDB::register_virtual_class<Shader>(); + ClassDB::register_class<ParticlesMaterial>(); + SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); + ParticlesMaterial::init_shaders(); #ifndef _3D_DISABLED ClassDB::register_virtual_class<Mesh>(); @@ -575,10 +583,6 @@ void register_scene_types() { SceneTree::add_idle_callback(SpatialMaterial::flush_changes); SpatialMaterial::init_shaders(); - ClassDB::register_class<ParticlesMaterial>(); - SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); - ParticlesMaterial::init_shaders(); - ClassDB::register_class<MultiMesh>(); ClassDB::register_class<MeshLibrary>(); 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..4df849df6a 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; @@ -1036,6 +1034,8 @@ SelfList<DynamicFont>::List DynamicFont::dynamic_fonts; DynamicFont::DynamicFont() : font_list(this) { + cache_id.size = 16; + outline_cache_id.size = 16; spacing_top = 0; spacing_bottom = 0; spacing_char = 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..e6ef956dc5 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -482,6 +482,11 @@ void Mesh::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint"); + ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count); + ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays); + ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays); + ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &Mesh::surface_get_material); + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); @@ -1241,7 +1246,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) { @@ -1313,7 +1318,6 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode); ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); - ClassDB::bind_method(D_METHOD("get_surface_count"), &ArrayMesh::get_surface_count); ClassDB::bind_method(D_METHOD("surface_remove", "surf_idx"), &ArrayMesh::surface_remove); ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region); ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len); @@ -1321,12 +1325,9 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format); ClassDB::bind_method(D_METHOD("surface_get_primitive_type", "surf_idx"), &ArrayMesh::surface_get_primitive_type); ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &ArrayMesh::surface_set_material); - ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &ArrayMesh::surface_get_material); ClassDB::bind_method(D_METHOD("surface_find_by_name", "name"), &ArrayMesh::surface_find_by_name); ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name); ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name); - ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &ArrayMesh::surface_get_arrays); - ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &ArrayMesh::surface_get_blend_shape_arrays); ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape); ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape); ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline); @@ -1334,7 +1335,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/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 96edb17eea..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); @@ -946,30 +1022,12 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const { //this might not necessarily work well if using a rect, needs to be fixed properly - Rect2 rc = region; - if (!atlas.is_valid()) return; - Rect2 src = p_src_rect; - src.position += (rc.position - margin.position); - Rect2 src_c = rc.clip(src); - if (src_c.size == Size2()) - return; - Vector2 ofs = (src_c.position - src.position); - - Vector2 scale = p_rect.size / p_src_rect.size; - if (scale.x < 0) { - float mx = (margin.size.width - margin.position.x); - mx -= margin.position.x; - ofs.x = -(ofs.x + mx); - } - if (scale.y < 0) { - float my = margin.size.height - margin.position.y; - my -= margin.position.y; - ofs.y = -(ofs.y + my); - } - Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale); + Rect2 dr; + Rect2 src_c; + get_rect_region(p_rect, p_src_rect, dr, src_c); RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, filter_clip); @@ -983,13 +1041,17 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, return false; Rect2 src = p_src_rect; + if (src.size == Size2()) { + src.size = rc.size; + } + Vector2 scale = p_rect.size / src.size; + src.position += (rc.position - margin.position); Rect2 src_c = rc.clip(src); if (src_c.size == Size2()) return false; Vector2 ofs = (src_c.position - src.position); - Vector2 scale = p_rect.size / p_src_rect.size; if (scale.x < 0) { float mx = (margin.size.width - margin.position.x); mx -= margin.position.x; @@ -1007,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; } @@ -1184,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() { } @@ -1666,7 +1754,7 @@ ProxyTexture::~ProxyTexture() { void AnimatedTexture::_update_proxy() { - _THREAD_SAFE_METHOD_ + RWLockRead r(rw_lock); float delta; if (prev_ticks == 0) { @@ -1712,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; } @@ -1723,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; } @@ -1738,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; } @@ -1760,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; @@ -1770,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; @@ -1785,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; @@ -1796,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>(); @@ -1805,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; @@ -1862,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); + } } /////////////////////////////// @@ -1990,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/tile_set.cpp b/scene/resources/tile_set.cpp index 3d2b6c36de..8112d6be00 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -59,7 +59,13 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { tile_set_region(id, p_value); else if (what == "tile_mode") tile_set_tile_mode(id, (TileMode)((int)p_value)); - else if (what.left(9) == "autotile/") { + else if (what == "is_autotile") { + // backward compatibility for Godot 3.0.x + // autotile used to be a bool, it's now an enum + bool is_autotile = p_value; + if (is_autotile) + tile_set_tile_mode(id, AUTO_TILE); + } else if (what.left(9) == "autotile/") { what = what.right(9); if (what == "bitmask_mode") autotile_set_bitmask_mode(id, (BitmaskMode)((int)p_value)); @@ -950,6 +956,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_region", "id"), &TileSet::tile_get_region); ClassDB::bind_method(D_METHOD("tile_set_shape", "id", "shape_id", "shape"), &TileSet::tile_set_shape); ClassDB::bind_method(D_METHOD("tile_get_shape", "id", "shape_id"), &TileSet::tile_get_shape); + ClassDB::bind_method(D_METHOD("tile_set_shape_offset", "id", "shape_id", "shape_offset"), &TileSet::tile_set_shape_offset); + ClassDB::bind_method(D_METHOD("tile_get_shape_offset", "id", "shape_id"), &TileSet::tile_get_shape_offset); ClassDB::bind_method(D_METHOD("tile_set_shape_transform", "id", "shape_id", "shape_transform"), &TileSet::tile_set_shape_transform); ClassDB::bind_method(D_METHOD("tile_get_shape_transform", "id", "shape_id"), &TileSet::tile_get_shape_transform); ClassDB::bind_method(D_METHOD("tile_set_shape_one_way", "id", "shape_id", "one_way"), &TileSet::tile_set_shape_one_way); 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 }; |