diff options
Diffstat (limited to 'scene/3d')
40 files changed, 1871 insertions, 246 deletions
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 4089d80d4e..21f471039f 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -169,7 +169,7 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo E->get().in_tree = node && node->is_inside_tree(); if (node) { node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); } @@ -196,7 +196,7 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); if (E->get().in_tree) emit_signal(SceneStringNames::get_singleton()->body_exited, obj); } @@ -246,7 +246,7 @@ void Area::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->body_exited, obj); node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); } } @@ -276,7 +276,7 @@ void Area::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->area_exited, obj); node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree); } } } @@ -366,7 +366,7 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar E->get().in_tree = node && node->is_inside_tree(); if (node) { node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree, make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->area_entered, node); } @@ -393,7 +393,7 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->area_exited, obj); } diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index cf2a47f14c..c2a50ec7bb 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -57,18 +57,18 @@ void AudioStreamPlayer3D::_mix_audio() { //mix if (output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) { - float pitch_scale = 0.0; + float output_pitch_scale = 0.0; if (output_count) { //used for doppler, not realistic but good enough for (int i = 0; i < output_count; i++) { - pitch_scale += outputs[i].pitch_scale; + output_pitch_scale += outputs[i].pitch_scale; } - pitch_scale /= float(output_count); + output_pitch_scale /= float(output_count); } else { - pitch_scale = 1.0; + output_pitch_scale = 1.0; } - stream_playback->mix(buffer, pitch_scale, buffer_size); + stream_playback->mix(buffer, pitch_scale * output_pitch_scale, buffer_size); } //write all outputs @@ -320,7 +320,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { total_max = MAX(total_max, cam_area_pos.length()); } if (total_max > max_distance) { - continue; //cant hear this sound in this camera + continue; //can't hear this sound in this camera } } @@ -536,14 +536,14 @@ void AudioStreamPlayer3D::_notification(int p_what) { setseek = setplay; active = true; setplay = -1; - //do not update, this makes it easier to animate (will shut off otherise) + //do not update, this makes it easier to animate (will shut off otherwise) ///_change_notify("playing"); //update property in editor } //stop playing if no longer active if (!active) { set_physics_process_internal(false); - //do not update, this makes it easier to animate (will shut off otherise) + //do not update, this makes it easier to animate (will shut off otherwise) //_change_notify("playing"); //update property in editor emit_signal("finished"); } @@ -607,6 +607,13 @@ float AudioStreamPlayer3D::get_max_db() const { return max_db; } +void AudioStreamPlayer3D::set_pitch_scale(float p_pitch_scale) { + pitch_scale = p_pitch_scale; +} +float AudioStreamPlayer3D::get_pitch_scale() const { + return pitch_scale; +} + void AudioStreamPlayer3D::play(float p_from_pos) { if (stream_playback.is_valid()) { @@ -832,6 +839,9 @@ void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_max_db", "max_db"), &AudioStreamPlayer3D::set_max_db); ClassDB::bind_method(D_METHOD("get_max_db"), &AudioStreamPlayer3D::get_max_db); + ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer3D::set_pitch_scale); + ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer3D::get_pitch_scale); + ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer3D::play, DEFVAL(0.0)); ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer3D::seek); ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer3D::stop); @@ -885,6 +895,7 @@ void AudioStreamPlayer3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,65536,1"), "set_max_distance", "get_max_distance"); @@ -921,6 +932,7 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() { unit_size = 1; attenuation_model = ATTENUATION_INVERSE_DISTANCE; max_db = 3; + pitch_scale = 1.0; autoplay = false; setseek = -1; active = false; diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 9a1f369da2..1fcb83cf21 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -106,6 +106,7 @@ private: float unit_db; float unit_size; float max_db; + float pitch_scale; bool autoplay; StringName bus; @@ -153,6 +154,9 @@ public: void set_max_db(float p_boost); float get_max_db() const; + void set_pitch_scale(float p_pitch_scale); + float get_pitch_scale() const; + void play(float p_from_pos = 0.0); void seek(float p_seconds); void stop(); diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 96eb7eb6f4..204aaef7ec 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -170,11 +170,11 @@ void BakedLightmapData::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users); ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_user_data", "_get_user_data"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data"); } BakedLightmapData::BakedLightmapData() { @@ -316,7 +316,7 @@ bool BakedLightmap::_bake_time(void *ud, float p_secs, float p_progress) { int mins_left = p_secs / 60; int secs_left = Math::fmod(p_secs, 60.0f); int percent = p_progress * 100; - bool abort = bake_step_function(btd->pass + percent, btd->text + " " + itos(percent) + "% (Time Left: " + itos(mins_left) + ":" + itos(secs_left) + "s)"); + bool abort = bake_step_function(btd->pass + percent, btd->text + " " + vformat(RTR("%d%%"), percent) + " " + vformat(RTR("(Time Left: %d:%02d s)"), mins_left, secs_left)); btd->last_step = time; if (abort) return true; @@ -784,7 +784,7 @@ void BakedLightmap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size"); ADD_GROUP("Data", ""); ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedIndirectLightData"), "set_light_data", "get_light_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedLightmapData"), "set_light_data", "get_light_data"); BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW); BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM); diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp index 3882b8548b..a875b65c22 100644 --- a/scene/3d/bone_attachment.cpp +++ b/scene/3d/bone_attachment.cpp @@ -30,43 +30,27 @@ #include "bone_attachment.h" -bool BoneAttachment::_get(const StringName &p_name, Variant &r_ret) const { +void BoneAttachment::_validate_property(PropertyInfo &property) const { - if (String(p_name) == "bone_name") { + if (property.name == "bone_name") { + Skeleton *parent = Object::cast_to<Skeleton>(get_parent()); - r_ret = get_bone_name(); - return true; - } - - return false; -} -bool BoneAttachment::_set(const StringName &p_name, const Variant &p_value) { - - if (String(p_name) == "bone_name") { - - set_bone_name(p_value); - return true; - } + if (parent) { - return false; -} -void BoneAttachment::_get_property_list(List<PropertyInfo> *p_list) const { - - Skeleton *parent = Object::cast_to<Skeleton>(get_parent()); + String names; + for (int i = 0; i < parent->get_bone_count(); i++) { + if (i > 0) + names += ","; + names += parent->get_bone_name(i); + } - if (parent) { + property.hint = PROPERTY_HINT_ENUM; + property.hint_string = names; + } else { - String names; - for (int i = 0; i < parent->get_bone_count(); i++) { - if (i > 0) - names += ","; - names += parent->get_bone_name(i); + property.hint = PROPERTY_HINT_NONE; + property.hint_string = ""; } - - p_list->push_back(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM, names)); - } else { - - p_list->push_back(PropertyInfo(Variant::STRING, "bone_name")); } } @@ -138,4 +122,6 @@ BoneAttachment::BoneAttachment() { void BoneAttachment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &BoneAttachment::set_bone_name); ClassDB::bind_method(D_METHOD("get_bone_name"), &BoneAttachment::get_bone_name); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "bone_name"), "set_bone_name", "get_bone_name"); } diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h index fa31642354..81a225015e 100644 --- a/scene/3d/bone_attachment.h +++ b/scene/3d/bone_attachment.h @@ -44,9 +44,7 @@ class BoneAttachment : public Spatial { void _check_unbind(); protected: - bool _get(const StringName &p_name, Variant &r_ret) const; - bool _set(const StringName &p_name, const Variant &p_value); - void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void _validate_property(PropertyInfo &property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 6998b34cfd..9de189c158 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -201,7 +201,7 @@ void Camera::make_current() { //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this); } -void Camera::clear_current() { +void Camera::clear_current(bool p_enable_next) { current = false; if (!is_inside_tree()) @@ -209,7 +209,10 @@ void Camera::clear_current() { if (get_viewport()->get_camera() == this) { get_viewport()->_camera_set(NULL); - get_viewport()->_camera_make_next_current(this); + + if (p_enable_next) { + get_viewport()->_camera_make_next_current(this); + } } } @@ -439,7 +442,7 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective); ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal); ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current); - ClassDB::bind_method(D_METHOD("clear_current"), &Camera::clear_current); + ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current); ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform); diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 3fd3303a25..1b506e0c4f 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -97,7 +97,7 @@ protected: void _update_camera_mode(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const; + virtual void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); @@ -113,7 +113,7 @@ public: void set_projection(Camera::Projection p_mode); void make_current(); - void clear_current(); + void clear_current(bool p_enable_next = true); void set_current(bool p_current); bool is_current() const; @@ -132,9 +132,9 @@ public: virtual Transform get_camera_transform() const; - Vector3 project_ray_normal(const Point2 &p_pos) const; + virtual Vector3 project_ray_normal(const Point2 &p_pos) const; virtual Vector3 project_ray_origin(const Point2 &p_pos) const; - Vector3 project_local_ray_normal(const Point2 &p_pos) const; + virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; virtual Vector3 project_position(const Point2 &p_point) const; diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index b246fe75f4..1d5d1b2afe 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -365,6 +365,20 @@ bool CollisionObject::get_capture_input_on_drag() const { return capture_input_on_drag; } +String CollisionObject::get_configuration_warning() const { + + String warning = Spatial::get_configuration_warning(); + + if (shapes.empty()) { + if (warning == String()) { + warning += "\n"; + } + warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape or CollisionPolygon as a child to define its shape."); + } + + return warning; +} + CollisionObject::CollisionObject() { capture_input_on_drag = false; diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index c58e02848f..f31d65e411 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -109,6 +109,8 @@ public: _FORCE_INLINE_ RID get_rid() const { return rid; } + virtual String get_configuration_warning() const; + CollisionObject(); ~CollisionObject(); }; diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index ef1b33a4e2..379dd21c39 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -73,6 +73,14 @@ void CollisionPolygon::_build_polygon() { } } +void CollisionPolygon::_update_in_shape_owner(bool p_xform_only) { + + parent->shape_owner_set_transform(owner_id, get_transform()); + if (p_xform_only) + return; + parent->shape_owner_set_disabled(owner_id, disabled); +} + void CollisionPolygon::_notification(int p_what) { switch (p_what) { @@ -82,14 +90,20 @@ void CollisionPolygon::_notification(int p_what) { if (parent) { owner_id = parent->create_shape_owner(this); _build_polygon(); - parent->shape_owner_set_transform(owner_id, get_transform()); - parent->shape_owner_set_disabled(owner_id, disabled); + _update_in_shape_owner(); } } break; + case NOTIFICATION_ENTER_TREE: { + + if (parent) { + _update_in_shape_owner(); + } + + } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { - parent->shape_owner_set_transform(owner_id, get_transform()); + _update_in_shape_owner(true); } } break; @@ -159,6 +173,9 @@ String CollisionPolygon::get_configuration_warning() const { return String(); } +bool CollisionPolygon::_is_editable_3d_polygon() const { + return true; +} void CollisionPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth); @@ -170,6 +187,8 @@ void CollisionPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled); + ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h index 6643cfa044..f1f137c9c5 100644 --- a/scene/3d/collision_polygon.h +++ b/scene/3d/collision_polygon.h @@ -51,6 +51,10 @@ protected: void _build_polygon(); + void _update_in_shape_owner(bool p_xform_only = false); + + bool _is_editable_3d_polygon() const; + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp index d6d49a197c..943f4158f7 100644 --- a/scene/3d/collision_shape.cpp +++ b/scene/3d/collision_shape.cpp @@ -64,6 +64,14 @@ void CollisionShape::make_convex_from_brothers() { } } +void CollisionShape::_update_in_shape_owner(bool p_xform_only) { + + parent->shape_owner_set_transform(owner_id, get_transform()); + if (p_xform_only) + return; + parent->shape_owner_set_disabled(owner_id, disabled); +} + void CollisionShape::_notification(int p_what) { switch (p_what) { @@ -75,19 +83,20 @@ void CollisionShape::_notification(int p_what) { if (shape.is_valid()) { parent->shape_owner_add_shape(owner_id, shape); } - parent->shape_owner_set_transform(owner_id, get_transform()); - parent->shape_owner_set_disabled(owner_id, disabled); + _update_in_shape_owner(); } } break; case NOTIFICATION_ENTER_TREE: { + if (parent) { + _update_in_shape_owner(); + } if (get_tree()->is_debugging_collisions_hint()) { _create_debug_shape(); } - } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { - parent->shape_owner_set_transform(owner_id, get_transform()); + _update_in_shape_owner(true); } } break; case NOTIFICATION_UNPARENTED: { diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h index 724a025165..c9c91a5824 100644 --- a/scene/3d/collision_shape.h +++ b/scene/3d/collision_shape.h @@ -51,6 +51,8 @@ class CollisionShape : public Spatial { void _create_debug_shape(); + void _update_in_shape_owner(bool p_xform_only = false); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index ce9e801385..4ad2eb60ee 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -535,7 +535,7 @@ void GIProbe::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_normal_bias", "get_normal_bias"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compress"), "set_compress", "is_compressed"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData"), "set_probe_data", "get_probe_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); BIND_ENUM_CONSTANT(SUBDIV_64); BIND_ENUM_CONSTANT(SUBDIV_128); diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp index 9865fe156a..ffa283f634 100644 --- a/scene/3d/interpolated_camera.cpp +++ b/scene/3d/interpolated_camera.cpp @@ -38,10 +38,10 @@ void InterpolatedCamera::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { if (Engine::get_singleton()->is_editor_hint() && enabled) - set_physics_process(false); + set_process_internal(false); } break; - case NOTIFICATION_PROCESS: { + case NOTIFICATION_INTERNAL_PROCESS: { if (!enabled) break; @@ -111,9 +111,9 @@ void InterpolatedCamera::set_interpolation_enabled(bool p_enable) { if (p_enable) { if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) return; - set_process(true); + set_process_internal(true); } else - set_process(false); + set_process_internal(false); } bool InterpolatedCamera::is_interpolation_enabled() const { diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index e7ab6cde8a..77bf703706 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -35,6 +35,7 @@ void Navigation::_navmesh_link(int p_id) { ERR_FAIL_COND(!navmesh_map.has(p_id)); NavMesh &nm = navmesh_map[p_id]; ERR_FAIL_COND(nm.linked); + ERR_FAIL_COND(nm.navmesh.is_null()); PoolVector<Vector3> vertices = nm.navmesh->get_vertices(); int len = vertices.size(); diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 5ec5b8b6c7..073e56fdb4 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -405,8 +405,8 @@ void NavigationMesh::_bind_methods() { BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE); BIND_CONSTANT(SAMPLE_PARTITION_LAYERS); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_polygons", "_get_polygons"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type"); diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 219464ae1f..a39ac5a8f5 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -849,9 +849,9 @@ void ParticlesMaterial::_update_shader() { code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; if (color_ramp.is_valid()) { - code += " COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n"; + code += " COLOR = hue_rot_mat * textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0);\n"; } else { - code += " COLOR = color_value * hue_rot_mat;\n"; + code += " COLOR = hue_rot_mat * color_value;\n"; } if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) { code += " COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n"; @@ -1028,8 +1028,6 @@ void ParticlesMaterial::set_param(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value); } break; - case PARAM_MAX: { - }; } } float ParticlesMaterial::get_param(Parameter p_param) const { @@ -1082,8 +1080,6 @@ void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) { case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value); } break; - case PARAM_MAX: { - }; } } float ParticlesMaterial::get_param_randomness(Parameter p_param) const { @@ -1160,8 +1156,6 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> case PARAM_ANIM_OFFSET: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); } break; - case PARAM_MAX: { - }; } _queue_shader_change(); @@ -1233,28 +1227,19 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) { emission_point_texture = p_points; - RID texture; - if (p_points.is_valid()) - texture = p_points->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points); } void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) { emission_normal_texture = p_normals; - RID texture; - if (p_normals.is_valid()) - texture = p_normals->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals); } void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) { emission_color_texture = p_colors; - RID texture; - if (p_colors.is_valid()) - texture = p_colors->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors); _queue_shader_change(); } @@ -1316,10 +1301,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail curve->ensure_default_setup(); } - RID texture; - if (p_trail_size_modifier.is_valid()) - texture = p_trail_size_modifier->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve); _queue_shader_change(); } @@ -1331,10 +1313,7 @@ Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { trail_color_modifier = p_trail_color_modifier; - RID texture; - if (p_trail_color_modifier.is_valid()) - texture = p_trail_color_modifier->get_rid(); - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture); + VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier); _queue_shader_change(); } @@ -1597,4 +1576,21 @@ ParticlesMaterial::ParticlesMaterial() : } ParticlesMaterial::~ParticlesMaterial() { + + if (material_mutex) + material_mutex->lock(); + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + + VS::get_singleton()->material_set_shader(_get_material(), RID()); + } + + if (material_mutex) + material_mutex->unlock(); } diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index afe4dd3f46..57d79c960f 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -40,6 +40,9 @@ void Path::_curve_changed() { if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) update_gizmo(); + if (is_inside_tree()) { + emit_signal("curve_changed"); + } } void Path::set_curve(const Ref<Curve3D> &p_curve) { @@ -68,6 +71,8 @@ void Path::_bind_methods() { ClassDB::bind_method(D_METHOD("_curve_changed"), &Path::_curve_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve"); + + ADD_SIGNAL(MethodInfo("curve_changed")); } Path::Path() { @@ -190,61 +195,16 @@ bool PathFollow::get_cubic_interpolation() const { return cubic; } -bool PathFollow::_set(const StringName &p_name, const Variant &p_value) { - - if (p_name == SceneStringNames::get_singleton()->offset) { - set_offset(p_value); - } else if (p_name == SceneStringNames::get_singleton()->unit_offset) { - set_unit_offset(p_value); - } else if (p_name == SceneStringNames::get_singleton()->rotation_mode) { - set_rotation_mode(RotationMode(p_value.operator int())); - } else if (p_name == SceneStringNames::get_singleton()->v_offset) { - set_v_offset(p_value); - } else if (p_name == SceneStringNames::get_singleton()->h_offset) { - set_h_offset(p_value); - } else if (String(p_name) == "cubic_interp") { - set_cubic_interpolation(p_value); - } else if (String(p_name) == "loop") { - set_loop(p_value); - } else - return false; - - return true; -} +void PathFollow::_validate_property(PropertyInfo &property) const { -bool PathFollow::_get(const StringName &p_name, Variant &r_ret) const { - - if (p_name == SceneStringNames::get_singleton()->offset) { - r_ret = get_offset(); - } else if (p_name == SceneStringNames::get_singleton()->unit_offset) { - r_ret = get_unit_offset(); - } else if (p_name == SceneStringNames::get_singleton()->rotation_mode) { - r_ret = get_rotation_mode(); - } else if (p_name == SceneStringNames::get_singleton()->v_offset) { - r_ret = get_v_offset(); - } else if (p_name == SceneStringNames::get_singleton()->h_offset) { - r_ret = get_h_offset(); - } else if (String(p_name) == "cubic_interp") { - r_ret = cubic; - } else if (String(p_name) == "loop") { - r_ret = loop; - } else - return false; - - return true; -} -void PathFollow::_get_property_list(List<PropertyInfo> *p_list) const { - - float max = 10000; - if (path && path->get_curve().is_valid()) - max = path->get_curve()->get_baked_length(); - p_list->push_back(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0," + rtos(max) + ",0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::REAL, "h_offset")); - p_list->push_back(PropertyInfo(Variant::REAL, "v_offset")); - p_list->push_back(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ")); - p_list->push_back(PropertyInfo(Variant::BOOL, "cubic_interp")); - p_list->push_back(PropertyInfo(Variant::BOOL, "loop")); + if (property.name == "offset") { + + float max = 10000; + if (path && path->get_curve().is_valid()) + max = path->get_curve()->get_baked_length(); + + property.hint_string = "0," + rtos(max) + ",0.01"; + } } void PathFollow::_bind_methods() { @@ -270,6 +230,14 @@ void PathFollow::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop); ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ"), "set_rotation_mode", "get_rotation_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); + BIND_ENUM_CONSTANT(ROTATION_NONE); BIND_ENUM_CONSTANT(ROTATION_Y); BIND_ENUM_CONSTANT(ROTATION_XY); diff --git a/scene/3d/path.h b/scene/3d/path.h index fe57103d25..2ed686ac3c 100644 --- a/scene/3d/path.h +++ b/scene/3d/path.h @@ -79,9 +79,7 @@ private: void _update_transform(); 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; + virtual void _validate_property(PropertyInfo &property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 7d638d8737..4528799985 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -34,6 +34,10 @@ #include "method_bind_ext.gen.inc" #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED +#include "editor/plugins/spatial_editor_plugin.h" +#endif + void PhysicsBody::_notification(int p_what) { /* @@ -258,6 +262,7 @@ void RigidBody::_body_enter_tree(ObjectID p_id) { Node *node = Object::cast_to<Node>(obj); ERR_FAIL_COND(!node); + ERR_FAIL_COND(!contact_monitor); Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id); ERR_FAIL_COND(!E); ERR_FAIL_COND(E->get().in_tree); @@ -281,6 +286,7 @@ void RigidBody::_body_exit_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = Object::cast_to<Node>(obj); ERR_FAIL_COND(!node); + ERR_FAIL_COND(!contact_monitor); Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id); ERR_FAIL_COND(!E); ERR_FAIL_COND(!E->get().in_tree); @@ -306,6 +312,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, Object *obj = ObjectDB::get_instance(objid); Node *node = Object::cast_to<Node>(obj); + ERR_FAIL_COND(!contact_monitor); Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid); ERR_FAIL_COND(!body_in && !E); @@ -318,7 +325,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, E->get().in_tree = node && node->is_inside_tree(); if (node) { node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid)); if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); } @@ -345,7 +352,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); if (in_tree) emit_signal(SceneStringNames::get_singleton()->body_exited, obj); } @@ -367,9 +374,7 @@ struct _RigidBodyInOut { void RigidBody::_direct_state_changed(Object *p_state) { -//eh.. fuck #ifdef DEBUG_ENABLED - state = Object::cast_to<PhysicsDirectBodyState>(p_state); #else state = (PhysicsDirectBodyState *)p_state; //trust it @@ -693,6 +698,10 @@ void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) { PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); } +void RigidBody::apply_torque_impulse(const Vector3 &p_impulse) { + PhysicsServer::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse); +} + void RigidBody::set_use_continuous_collision_detection(bool p_enable) { ccd = p_enable; @@ -719,6 +728,14 @@ void RigidBody::set_contact_monitor(bool p_enabled) { for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) { //clean up mess + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = Object::cast_to<Node>(obj); + + if (node) { + + node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree); + } } memdelete(contact_monitor); @@ -768,11 +785,11 @@ String RigidBody::get_configuration_warning() const { String warning = CollisionObject::get_configuration_warning(); - if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) { + if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { if (warning != String()) { warning += "\n"; } - warning += TTR("Size changes to RigidBody (in character or rigid modes) will be overriden by the physics engine when running.\nChange the size in children collision shapes instead."); + warning += TTR("Size changes to RigidBody (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); } return warning; @@ -824,6 +841,7 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity); ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody::apply_impulse); + ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody::apply_torque_impulse); ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody::set_sleeping); ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody::is_sleeping); @@ -914,10 +932,10 @@ RigidBody::~RigidBody() { ////////////////////////////////////////////////////// ////////////////////////// -Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion) { +Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia) { Collision col; - if (move_and_collide(p_motion, col)) { + if (move_and_collide(p_motion, p_infinite_inertia, col)) { if (motion_cache.is_null()) { motion_cache.instance(); motion_cache->owner = this; @@ -931,11 +949,11 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion) { return Ref<KinematicCollision>(); } -bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_collision) { +bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision) { Transform gt = get_global_transform(); PhysicsServer::MotionResult result; - bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, &result); + bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result); if (colliding) { r_collision.collider_metadata = result.collider_metadata; @@ -961,7 +979,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli return colliding; } -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) { +Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { Vector3 lv = p_linear_velocity; @@ -983,7 +1001,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve Collision collision; - bool collided = move_and_collide(motion, collision); + bool collided = move_and_collide(motion, p_infinite_inertia, collision); if (collided) { @@ -1056,11 +1074,11 @@ Vector3 KinematicBody::get_floor_velocity() const { return floor_velocity; } -bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion) { +bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) { ERR_FAIL_COND_V(!is_inside_tree(), false); - return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion); + return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia); } void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) { @@ -1109,10 +1127,10 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) { void KinematicBody::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec"), &KinematicBody::_move); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); + 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", "infinite_inertia", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody::test_move); + ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move); ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody::is_on_floor); ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody::is_on_ceiling); @@ -1252,3 +1270,1108 @@ KinematicCollision::KinematicCollision() { collision.local_shape = 0; owner = NULL; } + +/////////////////////////////////////// + +bool PhysicalBone::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + return false; +} + +bool PhysicalBone::JointData::_get(const StringName &p_name, Variant &r_ret) const { + return false; +} + +void PhysicalBone::JointData::_get_property_list(List<PropertyInfo> *p_list) const { +} + +bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + if ("joint_constraints/bias" == p_name) { + bias = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_BIAS, bias); + + } else if ("joint_constraints/damping" == p_name) { + damping = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_DAMPING, damping); + + } else if ("joint_constraints/impulse_clamp" == p_name) { + impulse_clamp = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp); + + } else { + return false; + } + + return true; +} + +bool PhysicalBone::PinJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/bias" == p_name) { + r_ret = bias; + } else if ("joint_constraints/damping" == p_name) { + r_ret = damping; + } else if ("joint_constraints/impulse_clamp" == p_name) { + r_ret = impulse_clamp; + } else { + return false; + } + + return true; +} + +void PhysicalBone::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01")); +} + +bool PhysicalBone::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + if ("joint_constraints/swing_span" == p_name) { + swing_span = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, swing_span); + + } else if ("joint_constraints/twist_span" == p_name) { + twist_span = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, twist_span); + + } else if ("joint_constraints/bias" == p_name) { + bias = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_BIAS, bias); + + } else if ("joint_constraints/softness" == p_name) { + softness = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, softness); + + } else if ("joint_constraints/relaxation" == p_name) { + relaxation = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, relaxation); + + } else { + return false; + } + + return true; +} + +bool PhysicalBone::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/swing_span" == p_name) { + r_ret = Math::rad2deg(swing_span); + } else if ("joint_constraints/twist_span" == p_name) { + r_ret = Math::rad2deg(twist_span); + } else if ("joint_constraints/bias" == p_name) { + r_ret = bias; + } else if ("joint_constraints/softness" == p_name) { + r_ret = softness; + } else if ("joint_constraints/relaxation" == p_name) { + r_ret = relaxation; + } else { + return false; + } + + return true; +} + +void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); +} + +bool PhysicalBone::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + if ("joint_constraints/angular_limit_enabled" == p_name) { + angular_limit_enabled = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->hinge_joint_set_flag(j, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled); + + } else if ("joint_constraints/angular_limit_upper" == p_name) { + angular_limit_upper = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper); + + } else if ("joint_constraints/angular_limit_lower" == p_name) { + angular_limit_lower = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower); + + } else if ("joint_constraints/angular_limit_bias" == p_name) { + angular_limit_bias = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias); + + } else if ("joint_constraints/angular_limit_softness" == p_name) { + angular_limit_softness = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness); + + } else if ("joint_constraints/angular_limit_relaxation" == p_name) { + angular_limit_relaxation = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation); + + } else { + return false; + } + + return true; +} + +bool PhysicalBone::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/angular_limit_enabled" == p_name) { + r_ret = angular_limit_enabled; + } else if ("joint_constraints/angular_limit_upper" == p_name) { + r_ret = Math::rad2deg(angular_limit_upper); + } else if ("joint_constraints/angular_limit_lower" == p_name) { + r_ret = Math::rad2deg(angular_limit_lower); + } else if ("joint_constraints/angular_limit_bias" == p_name) { + r_ret = angular_limit_bias; + } else if ("joint_constraints/angular_limit_softness" == p_name) { + r_ret = angular_limit_softness; + } else if ("joint_constraints/angular_limit_relaxation" == p_name) { + r_ret = angular_limit_relaxation; + } else { + return false; + } + + return true; +} + +void PhysicalBone::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/angular_limit_enabled")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01")); +} + +bool PhysicalBone::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + if ("joint_constraints/linear_limit_upper" == p_name) { + linear_limit_upper = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper); + + } else if ("joint_constraints/linear_limit_lower" == p_name) { + linear_limit_lower = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower); + + } else if ("joint_constraints/linear_limit_softness" == p_name) { + linear_limit_softness = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness); + + } else if ("joint_constraints/linear_limit_restitution" == p_name) { + linear_limit_restitution = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution); + + } else if ("joint_constraints/linear_limit_damping" == p_name) { + linear_limit_damping = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution); + + } else if ("joint_constraints/angular_limit_upper" == p_name) { + angular_limit_upper = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper); + + } else if ("joint_constraints/angular_limit_lower" == p_name) { + angular_limit_lower = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower); + + } else if ("joint_constraints/angular_limit_softness" == p_name) { + angular_limit_softness = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); + + } else if ("joint_constraints/angular_limit_restitution" == p_name) { + angular_limit_restitution = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness); + + } else if ("joint_constraints/angular_limit_damping" == p_name) { + angular_limit_damping = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping); + + } else { + return false; + } + + return true; +} + +bool PhysicalBone::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + if ("joint_constraints/linear_limit_upper" == p_name) { + r_ret = linear_limit_upper; + } else if ("joint_constraints/linear_limit_lower" == p_name) { + r_ret = linear_limit_lower; + } else if ("joint_constraints/linear_limit_softness" == p_name) { + r_ret = linear_limit_softness; + } else if ("joint_constraints/linear_limit_restitution" == p_name) { + r_ret = linear_limit_restitution; + } else if ("joint_constraints/linear_limit_damping" == p_name) { + r_ret = linear_limit_damping; + } else if ("joint_constraints/angular_limit_upper" == p_name) { + r_ret = Math::rad2deg(angular_limit_upper); + } else if ("joint_constraints/angular_limit_lower" == p_name) { + r_ret = Math::rad2deg(angular_limit_lower); + } else if ("joint_constraints/angular_limit_softness" == p_name) { + r_ret = angular_limit_softness; + } else if ("joint_constraints/angular_limit_restitution" == p_name) { + r_ret = angular_limit_restitution; + } else if ("joint_constraints/angular_limit_damping" == p_name) { + r_ret = angular_limit_damping; + } else { + return false; + } + + return true; +} + +void PhysicalBone::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const { + JointData::_get_property_list(p_list); + + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_upper")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_lower")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01")); + + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01")); +} + +bool PhysicalBone::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { + if (JointData::_set(p_name, p_value, j)) { + return true; + } + + String path = p_name; + + Vector3::Axis axis; + { + const String axis_s = path.get_slicec('/', 1); + if ("x" == axis_s) { + axis = Vector3::AXIS_X; + } else if ("y" == axis_s) { + axis = Vector3::AXIS_Y; + } else if ("z" == axis_s) { + axis = Vector3::AXIS_Z; + } else { + return false; + } + } + + String var_name = path.get_slicec('/', 2); + + if ("linear_limit_enabled" == var_name) { + axis_data[axis].linear_limit_enabled = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled); + + } else if ("linear_limit_upper" == var_name) { + axis_data[axis].linear_limit_upper = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper); + + } else if ("linear_limit_lower" == var_name) { + axis_data[axis].linear_limit_lower = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower); + + } else if ("linear_limit_softness" == var_name) { + axis_data[axis].linear_limit_softness = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness); + + } else if ("linear_restitution" == var_name) { + axis_data[axis].linear_restitution = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution); + + } else if ("linear_damping" == var_name) { + axis_data[axis].linear_damping = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping); + + } else if ("angular_limit_enabled" == var_name) { + axis_data[axis].angular_limit_enabled = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled); + + } else if ("angular_limit_upper" == var_name) { + axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper); + + } else if ("angular_limit_lower" == var_name) { + axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value)); + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower); + + } else if ("angular_limit_softness" == var_name) { + axis_data[axis].angular_limit_softness = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness); + + } else if ("angular_restitution" == var_name) { + axis_data[axis].angular_restitution = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution); + + } else if ("angular_damping" == var_name) { + axis_data[axis].angular_damping = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping); + + } else if ("erp" == var_name) { + axis_data[axis].erp = p_value; + if (j.is_valid()) + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp); + + } else { + return false; + } + + return true; +} + +bool PhysicalBone::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const { + if (JointData::_get(p_name, r_ret)) { + return true; + } + + String path = p_name; + + int axis; + { + const String axis_s = path.get_slicec('/', 1); + if ("x" == axis_s) { + axis = 0; + } else if ("y" == axis_s) { + axis = 1; + } else if ("z" == axis_s) { + axis = 2; + } else { + return false; + } + } + + String var_name = path.get_slicec('/', 2); + + if ("linear_limit_enabled" == var_name) { + r_ret = axis_data[axis].linear_limit_enabled; + } else if ("linear_limit_upper" == var_name) { + r_ret = axis_data[axis].linear_limit_upper; + } else if ("linear_limit_lower" == var_name) { + r_ret = axis_data[axis].linear_limit_lower; + } else if ("linear_limit_softness" == var_name) { + r_ret = axis_data[axis].linear_limit_softness; + } else if ("linear_restitution" == var_name) { + r_ret = axis_data[axis].linear_restitution; + } else if ("linear_damping" == var_name) { + r_ret = axis_data[axis].linear_damping; + } else if ("angular_limit_enabled" == var_name) { + r_ret = axis_data[axis].angular_limit_enabled; + } else if ("angular_limit_upper" == var_name) { + r_ret = Math::rad2deg(axis_data[axis].angular_limit_upper); + } else if ("angular_limit_lower" == var_name) { + r_ret = Math::rad2deg(axis_data[axis].angular_limit_lower); + } else if ("angular_limit_softness" == var_name) { + r_ret = axis_data[axis].angular_limit_softness; + } else if ("angular_restitution" == var_name) { + r_ret = axis_data[axis].angular_restitution; + } else if ("angular_damping" == var_name) { + r_ret = axis_data[axis].angular_damping; + } else if ("erp" == var_name) { + r_ret = axis_data[axis].erp; + } else { + return false; + } + + return true; +} + +void PhysicalBone::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const { + const StringName axis_names[] = { "x", "y", "z" }; + for (int i = 0; i < 3; ++i) { + p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_limit_enabled")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_upper")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_lower")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_limit_enabled")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/erp")); + } +} + +bool PhysicalBone::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "bone_name") { + set_bone_name(p_value); + return true; + } + + if (joint_data) { + if (joint_data->_set(p_name, p_value)) { +#ifdef TOOLS_ENABLED + if (get_gizmo().is_valid()) + get_gizmo()->redraw(); +#endif + return true; + } + } + + return false; +} + +bool PhysicalBone::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "bone_name") { + r_ret = get_bone_name(); + return true; + } + + if (joint_data) { + return joint_data->_get(p_name, r_ret); + } + + return false; +} + +void PhysicalBone::_get_property_list(List<PropertyInfo> *p_list) const { + + Skeleton *parent = find_skeleton_parent(get_parent()); + + if (parent) { + + String names; + for (int i = 0; i < parent->get_bone_count(); i++) { + if (i > 0) + names += ","; + names += parent->get_bone_name(i); + } + + p_list->push_back(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM, names)); + } else { + + p_list->push_back(PropertyInfo(Variant::STRING, "bone_name")); + } + + if (joint_data) { + joint_data->_get_property_list(p_list); + } +} + +void PhysicalBone::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + parent_skeleton = find_skeleton_parent(get_parent()); + update_bone_id(); + reset_to_rest_position(); + break; + case NOTIFICATION_EXIT_TREE: + if (parent_skeleton) { + if (-1 != bone_id) { + parent_skeleton->unbind_physical_bone_from_bone(bone_id); + } + } + parent_skeleton = NULL; + update_bone_id(); + break; + case NOTIFICATION_TRANSFORM_CHANGED: + if (Engine::get_singleton()->is_editor_hint()) { + + update_offset(); + } + break; + } +} + +void PhysicalBone::_direct_state_changed(Object *p_state) { + + if (!simulate_physics) { + return; + } + + /// Update bone transform + + PhysicsDirectBodyState *state; + +#ifdef DEBUG_ENABLED + state = Object::cast_to<PhysicsDirectBodyState>(p_state); +#else + state = (PhysicsDirectBodyState *)p_state; //trust it +#endif + + Transform global_transform(state->get_transform()); + + set_ignore_transform_notification(true); + set_global_transform(global_transform); + set_ignore_transform_notification(false); + + // Update skeleton + if (parent_skeleton) { + if (-1 != bone_id) { + parent_skeleton->set_bone_global_pose(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse)); + } + } +} + +void PhysicalBone::_bind_methods() { + ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone::_direct_state_changed); + + ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone::set_joint_type); + ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone::get_joint_type); + + ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone::set_joint_offset); + ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone::get_joint_offset); + + ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset); + ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset); + + ClassDB::bind_method(D_METHOD("set_static_body", "simulate"), &PhysicalBone::set_static_body); + ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body); + + ClassDB::bind_method(D_METHOD("set_simulate_physics", "simulate"), &PhysicalBone::set_simulate_physics); + ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics); + + ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); + + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass); + ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass); + + ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone::set_weight); + ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone::get_weight); + + ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone::set_friction); + ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone::get_friction); + + ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone::set_bounce); + ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone::get_bounce); + + ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone::set_gravity_scale); + ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone::get_gravity_scale); + + ADD_GROUP("Joint", "joint_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simulate_physics"), "set_simulate_physics", "get_simulate_physics"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "static_body"), "set_static_body", "is_static_body"); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); +} + +Skeleton *PhysicalBone::find_skeleton_parent(Node *p_parent) { + if (!p_parent) { + return NULL; + } + Skeleton *s = Object::cast_to<Skeleton>(p_parent); + return s ? s : find_skeleton_parent(p_parent->get_parent()); +} + +void PhysicalBone::_fix_joint_offset() { + // Clamp joint origin to bone origin + if (parent_skeleton) { + joint_offset.origin = body_offset.affine_inverse().origin; + } +} + +void PhysicalBone::_reload_joint() { + + if (joint.is_valid()) { + PhysicsServer::get_singleton()->free(joint); + joint = RID(); + } + + if (!parent_skeleton) { + return; + } + + PhysicalBone *body_a = parent_skeleton->get_physical_bone_parent(bone_id); + if (!body_a) { + return; + } + + Transform joint_transf = get_global_transform() * joint_offset; + Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf; + local_a.orthonormalize(); + + switch (get_joint_type()) { + case JOINT_TYPE_PIN: { + + joint = PhysicsServer::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); + const PinJointData *pjd(static_cast<const PinJointData *>(joint_data)); + PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_BIAS, pjd->bias); + PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_DAMPING, pjd->damping); + PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp); + + } break; + case JOINT_TYPE_CONE: { + + joint = PhysicsServer::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset); + const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data)); + PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span); + PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span); + PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_BIAS, cjd->bias); + PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, cjd->softness); + PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation); + + } break; + case JOINT_TYPE_HINGE: { + + joint = PhysicsServer::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset); + const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data)); + PhysicsServer::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled); + PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper); + PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower); + PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias); + PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness); + PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation); + + } break; + case JOINT_TYPE_SLIDER: { + + joint = PhysicsServer::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset); + const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data)); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness); + PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping); + + } break; + case JOINT_TYPE_6DOF: { + + joint = PhysicsServer::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, get_rid(), joint_offset); + const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data)); + for (int axis = 0; axis < 3; ++axis) { + PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping); + PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping); + PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp); + } + + } break; + } +} + +void PhysicalBone::_on_bone_parent_changed() { + _reload_joint(); +} + +void PhysicalBone::_set_gizmo_move_joint(bool p_move_joint) { +#ifdef TOOLS_ENABLED + gizmo_move_joint = p_move_joint; + SpatialEditor::get_singleton()->update_transform_gizmo(); +#endif +} + +#ifdef TOOLS_ENABLED +Transform PhysicalBone::get_global_gizmo_transform() const { + return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform(); +} + +Transform PhysicalBone::get_local_gizmo_transform() const { + return gizmo_move_joint ? get_transform() * joint_offset : get_transform(); +} +#endif + +const PhysicalBone::JointData *PhysicalBone::get_joint_data() const { + return joint_data; +} + +Skeleton *PhysicalBone::find_skeleton_parent() { + return find_skeleton_parent(this); +} + +void PhysicalBone::set_joint_type(JointType p_joint_type) { + + if (p_joint_type == get_joint_type()) + return; + + memdelete(joint_data); + joint_data = NULL; + switch (p_joint_type) { + case JOINT_TYPE_PIN: + joint_data = memnew(PinJointData); + break; + case JOINT_TYPE_CONE: + joint_data = memnew(ConeJointData); + break; + case JOINT_TYPE_HINGE: + joint_data = memnew(HingeJointData); + break; + case JOINT_TYPE_SLIDER: + joint_data = memnew(SliderJointData); + break; + case JOINT_TYPE_6DOF: + joint_data = memnew(SixDOFJointData); + break; + } + + _reload_joint(); + +#ifdef TOOLS_ENABLED + _change_notify(); + if (get_gizmo().is_valid()) + get_gizmo()->redraw(); +#endif +} + +PhysicalBone::JointType PhysicalBone::get_joint_type() const { + return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE; +} + +void PhysicalBone::set_joint_offset(const Transform &p_offset) { + joint_offset = p_offset; + + _fix_joint_offset(); + + set_ignore_transform_notification(true); + reset_to_rest_position(); + set_ignore_transform_notification(false); + +#ifdef TOOLS_ENABLED + if (get_gizmo().is_valid()) + get_gizmo()->redraw(); +#endif +} + +const Transform &PhysicalBone::get_body_offset() const { + return body_offset; +} + +void PhysicalBone::set_body_offset(const Transform &p_offset) { + body_offset = p_offset; + body_offset_inverse = body_offset.affine_inverse(); + + _fix_joint_offset(); + + set_ignore_transform_notification(true); + reset_to_rest_position(); + set_ignore_transform_notification(false); + +#ifdef TOOLS_ENABLED + if (get_gizmo().is_valid()) + get_gizmo()->redraw(); +#endif +} + +const Transform &PhysicalBone::get_joint_offset() const { + return joint_offset; +} + +void PhysicalBone::set_static_body(bool p_static) { + + static_body = p_static; + + set_as_toplevel(!static_body); + + _reset_physics_simulation_state(); +} + +bool PhysicalBone::is_static_body() { + return static_body; +} + +void PhysicalBone::set_simulate_physics(bool p_simulate) { + if (simulate_physics == p_simulate) { + return; + } + + simulate_physics = p_simulate; + _reset_physics_simulation_state(); +} + +bool PhysicalBone::get_simulate_physics() { + return simulate_physics; +} + +bool PhysicalBone::is_simulating_physics() { + return _internal_simulate_physics && !_internal_static_body; +} + +void PhysicalBone::set_bone_name(const String &p_name) { + + bone_name = p_name; + bone_id = -1; + + update_bone_id(); + reset_to_rest_position(); +} + +const String &PhysicalBone::get_bone_name() const { + + return bone_name; +} + +void PhysicalBone::set_mass(real_t p_mass) { + + ERR_FAIL_COND(p_mass <= 0); + mass = p_mass; + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_MASS, mass); +} + +real_t PhysicalBone::get_mass() const { + + return mass; +} + +void PhysicalBone::set_weight(real_t p_weight) { + + set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8))); +} + +real_t PhysicalBone::get_weight() const { + + return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)); +} + +void PhysicalBone::set_friction(real_t p_friction) { + + ERR_FAIL_COND(p_friction < 0 || p_friction > 1); + + friction = p_friction; + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction); +} + +real_t PhysicalBone::get_friction() const { + + return friction; +} + +void PhysicalBone::set_bounce(real_t p_bounce) { + + ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); + + bounce = p_bounce; + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce); +} +real_t PhysicalBone::get_bounce() const { + + return bounce; +} + +void PhysicalBone::set_gravity_scale(real_t p_gravity_scale) { + + gravity_scale = p_gravity_scale; + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_GRAVITY_SCALE, gravity_scale); +} + +real_t PhysicalBone::get_gravity_scale() const { + + return gravity_scale; +} + +PhysicalBone::PhysicalBone() : + PhysicsBody(PhysicsServer::BODY_MODE_STATIC), +#ifdef TOOLS_ENABLED + gizmo_move_joint(false), +#endif + joint_data(NULL), + static_body(false), + simulate_physics(false), + _internal_static_body(!static_body), + _internal_simulate_physics(simulate_physics), + bone_id(-1), + parent_skeleton(NULL), + bone_name(""), + bounce(0), + mass(1), + friction(1), + gravity_scale(1) { + + set_static_body(static_body); + _reset_physics_simulation_state(); +} + +PhysicalBone::~PhysicalBone() { + memdelete(joint_data); +} + +void PhysicalBone::update_bone_id() { + if (!parent_skeleton) { + return; + } + + const int new_bone_id = parent_skeleton->find_bone(bone_name); + + if (new_bone_id != bone_id) { + if (-1 != bone_id) { + // Assert the unbind from old node + parent_skeleton->unbind_physical_bone_from_bone(bone_id); + parent_skeleton->unbind_child_node_from_bone(bone_id, this); + } + + bone_id = new_bone_id; + + parent_skeleton->bind_physical_bone_to_bone(bone_id, this); + + _fix_joint_offset(); + _internal_static_body = !static_body; // Force staticness reset + _reset_staticness_state(); + } +} + +void PhysicalBone::update_offset() { +#ifdef TOOLS_ENABLED + if (parent_skeleton) { + + Transform bone_transform(parent_skeleton->get_global_transform()); + if (-1 != bone_id) + bone_transform *= parent_skeleton->get_bone_global_pose(bone_id); + + if (gizmo_move_joint) { + bone_transform *= body_offset; + set_joint_offset(bone_transform.affine_inverse() * get_global_transform()); + } else { + set_body_offset(bone_transform.affine_inverse() * get_global_transform()); + } + } +#endif +} + +void PhysicalBone::reset_to_rest_position() { + if (parent_skeleton) { + if (-1 == bone_id) { + set_global_transform(parent_skeleton->get_global_transform() * body_offset); + } else { + set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); + } + } +} + +void PhysicalBone::_reset_physics_simulation_state() { + if (simulate_physics && !static_body) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } + + _reset_staticness_state(); +} + +void PhysicalBone::_reset_staticness_state() { + + if (parent_skeleton && -1 != bone_id) { + if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary + + if (_internal_static_body) { + return; + } + + parent_skeleton->bind_child_node_to_bone(bone_id, this); + _internal_static_body = true; + } else { + + if (!_internal_static_body) { + return; + } + + parent_skeleton->unbind_child_node_from_bone(bone_id, this); + _internal_static_body = false; + } + } +} + +void PhysicalBone::_start_physics_simulation() { + if (_internal_simulate_physics || !parent_skeleton) { + return; + } + reset_to_rest_position(); + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_RIGID); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); + parent_skeleton->set_bone_ignore_animation(bone_id, true); + _internal_simulate_physics = true; +} + +void PhysicalBone::_stop_physics_simulation() { + if (!_internal_simulate_physics || !parent_skeleton) { + return; + } + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); + parent_skeleton->set_bone_ignore_animation(bone_id, false); + _internal_simulate_physics = false; +} diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index c7556c0c5f..17d2769c79 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -33,6 +33,7 @@ #include "scene/3d/collision_object.h" #include "servers/physics_server.h" +#include "skeleton.h" #include "vset.h" class PhysicsBody : public CollisionObject { @@ -242,6 +243,7 @@ public: Array get_colliding_bodies() const; void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); + void apply_torque_impulse(const Vector3 &p_impulse); virtual String get_configuration_warning() const; @@ -285,15 +287,15 @@ private: _FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const; - Ref<KinematicCollision> _move(const Vector3 &p_motion); + Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true); Ref<KinematicCollision> _get_slide_collision(int p_bounce); protected: static void _bind_methods(); public: - bool move_and_collide(const Vector3 &p_motion, Collision &r_collision); - bool test_move(const Transform &p_from, const Vector3 &p_motion); + bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision); + bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia); void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const; @@ -301,7 +303,7 @@ public: 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)); + Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 0.05, 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; @@ -341,4 +343,267 @@ public: KinematicCollision(); }; +class PhysicalBone : public PhysicsBody { + + GDCLASS(PhysicalBone, PhysicsBody); + +public: + enum JointType { + JOINT_TYPE_NONE, + JOINT_TYPE_PIN, + JOINT_TYPE_CONE, + JOINT_TYPE_HINGE, + JOINT_TYPE_SLIDER, + JOINT_TYPE_6DOF + }; + + struct JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_NONE; } + + /// "j" is used to set the parameter inside the PhysicsServer + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + }; + + struct PinJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_PIN; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + real_t bias; + real_t damping; + real_t impulse_clamp; + + PinJointData() : + bias(0.3), + damping(1.), + impulse_clamp(0) {} + }; + + struct ConeJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_CONE; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + real_t swing_span; + real_t twist_span; + real_t bias; + real_t softness; + real_t relaxation; + + ConeJointData() : + swing_span(Math_PI * 0.25), + twist_span(Math_PI), + bias(0.3), + softness(0.8), + relaxation(1.) {} + }; + + struct HingeJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + bool angular_limit_enabled; + real_t angular_limit_upper; + real_t angular_limit_lower; + real_t angular_limit_bias; + real_t angular_limit_softness; + real_t angular_limit_relaxation; + + HingeJointData() : + angular_limit_enabled(false), + angular_limit_upper(Math_PI * 0.5), + angular_limit_lower(-Math_PI * 0.5), + angular_limit_bias(0.3), + angular_limit_softness(0.9), + angular_limit_relaxation(1.) {} + }; + + struct SliderJointData : public JointData { + virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + real_t linear_limit_upper; + real_t linear_limit_lower; + real_t linear_limit_softness; + real_t linear_limit_restitution; + real_t linear_limit_damping; + real_t angular_limit_upper; + real_t angular_limit_lower; + real_t angular_limit_softness; + real_t angular_limit_restitution; + real_t angular_limit_damping; + + SliderJointData() : + linear_limit_upper(1.), + linear_limit_lower(-1.), + linear_limit_softness(1.), + linear_limit_restitution(0.7), + linear_limit_damping(1.), + angular_limit_upper(0), + angular_limit_lower(0), + angular_limit_softness(1.), + angular_limit_restitution(0.7), + angular_limit_damping(1.) {} + }; + + struct SixDOFJointData : public JointData { + struct SixDOFAxisData { + bool linear_limit_enabled; + real_t linear_limit_upper; + real_t linear_limit_lower; + real_t linear_limit_softness; + real_t linear_restitution; + real_t linear_damping; + bool angular_limit_enabled; + real_t angular_limit_upper; + real_t angular_limit_lower; + real_t angular_limit_softness; + real_t angular_restitution; + real_t angular_damping; + real_t erp; + + SixDOFAxisData() : + linear_limit_enabled(true), + linear_limit_upper(0), + linear_limit_lower(0), + linear_limit_softness(0.7), + linear_restitution(0.5), + linear_damping(1.), + angular_limit_enabled(true), + angular_limit_upper(0), + angular_limit_lower(0), + angular_limit_softness(0.5), + angular_restitution(0), + angular_damping(1.), + erp(0.5) {} + }; + + virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; } + + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _get(const StringName &p_name, Variant &r_ret) const; + virtual void _get_property_list(List<PropertyInfo> *p_list) const; + + SixDOFAxisData axis_data[3]; + + SixDOFJointData() {} + }; + +private: +#ifdef TOOLS_ENABLED + // if false gizmo move body + bool gizmo_move_joint; +#endif + + JointData *joint_data; + Transform joint_offset; + RID joint; + + Skeleton *parent_skeleton; + Transform body_offset; + Transform body_offset_inverse; + bool static_body; + bool _internal_static_body; + bool simulate_physics; + bool _internal_simulate_physics; + int bone_id; + + String bone_name; + real_t bounce; + real_t mass; + real_t friction; + real_t gravity_scale; + +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); + void _direct_state_changed(Object *p_state); + + static void _bind_methods(); + +private: + static Skeleton *find_skeleton_parent(Node *p_parent); + void _fix_joint_offset(); + void _reload_joint(); + +public: + void _on_bone_parent_changed(); + void _set_gizmo_move_joint(bool p_move_joint); + +public: +#ifdef TOOLS_ENABLED + virtual Transform get_global_gizmo_transform() const; + virtual Transform get_local_gizmo_transform() const; +#endif + + const JointData *get_joint_data() const; + Skeleton *find_skeleton_parent(); + + int get_bone_id() const { return bone_id; } + + void set_joint_type(JointType p_joint_type); + JointType get_joint_type() const; + + void set_joint_offset(const Transform &p_offset); + const Transform &get_joint_offset() const; + + void set_body_offset(const Transform &p_offset); + const Transform &get_body_offset() const; + + void set_static_body(bool p_static); + bool is_static_body(); + + void set_simulate_physics(bool p_simulate); + bool get_simulate_physics(); + bool is_simulating_physics(); + + void set_bone_name(const String &p_name); + const String &get_bone_name() const; + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_weight(real_t p_weight); + real_t get_weight() const; + + void set_friction(real_t p_friction); + real_t get_friction() const; + + void set_bounce(real_t p_bounce); + real_t get_bounce() const; + + void set_gravity_scale(real_t p_gravity_scale); + real_t get_gravity_scale() const; + + PhysicalBone(); + ~PhysicalBone(); + +private: + void update_bone_id(); + void update_offset(); + void reset_to_rest_position(); + + void _reset_physics_simulation_state(); + void _reset_staticness_state(); + + void _start_physics_simulation(); + void _stop_physics_simulation(); +}; + +VARIANT_ENUM_CAST(PhysicalBone::JointType); + #endif // PHYSICS_BODY__H diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index fed6d76f65..b2d10006f7 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -71,8 +71,7 @@ void Joint::_update_joint(bool p_only_free) { ba = body_a->get_rid(); bb = body_b->get_rid(); - if (exclude_from_collision) - PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); + PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } void Joint::set_node_a(const NodePath &p_node_a) { @@ -717,6 +716,9 @@ void Generic6DOFJoint::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x"); @@ -735,6 +737,9 @@ void Generic6DOFJoint::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y"); @@ -753,6 +758,9 @@ void Generic6DOFJoint::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z"); @@ -770,6 +778,8 @@ void Generic6DOFJoint::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS); BIND_ENUM_CONSTANT(PARAM_LINEAR_RESTITUTION); BIND_ENUM_CONSTANT(PARAM_LINEAR_DAMPING); + BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_TARGET_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_FORCE_LIMIT); BIND_ENUM_CONSTANT(PARAM_ANGULAR_LOWER_LIMIT); BIND_ENUM_CONSTANT(PARAM_ANGULAR_UPPER_LIMIT); BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS); @@ -784,6 +794,7 @@ void Generic6DOFJoint::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_LIMIT); BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_LIMIT); BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR); + BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_MOTOR); BIND_ENUM_CONSTANT(FLAG_MAX); } @@ -913,6 +924,8 @@ Generic6DOFJoint::Generic6DOFJoint() { set_param_x(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7); set_param_x(PARAM_LINEAR_RESTITUTION, 0.5); set_param_x(PARAM_LINEAR_DAMPING, 1.0); + set_param_x(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0); + set_param_x(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0); set_param_x(PARAM_ANGULAR_LOWER_LIMIT, 0); set_param_x(PARAM_ANGULAR_UPPER_LIMIT, 0); set_param_x(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f); @@ -926,12 +939,15 @@ Generic6DOFJoint::Generic6DOFJoint() { set_flag_x(FLAG_ENABLE_ANGULAR_LIMIT, true); set_flag_x(FLAG_ENABLE_LINEAR_LIMIT, true); set_flag_x(FLAG_ENABLE_MOTOR, false); + set_flag_x(FLAG_ENABLE_LINEAR_MOTOR, false); set_param_y(PARAM_LINEAR_LOWER_LIMIT, 0); set_param_y(PARAM_LINEAR_UPPER_LIMIT, 0); set_param_y(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7); set_param_y(PARAM_LINEAR_RESTITUTION, 0.5); set_param_y(PARAM_LINEAR_DAMPING, 1.0); + set_param_y(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0); + set_param_y(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0); set_param_y(PARAM_ANGULAR_LOWER_LIMIT, 0); set_param_y(PARAM_ANGULAR_UPPER_LIMIT, 0); set_param_y(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f); @@ -945,12 +961,15 @@ Generic6DOFJoint::Generic6DOFJoint() { set_flag_y(FLAG_ENABLE_ANGULAR_LIMIT, true); set_flag_y(FLAG_ENABLE_LINEAR_LIMIT, true); set_flag_y(FLAG_ENABLE_MOTOR, false); + set_flag_y(FLAG_ENABLE_LINEAR_MOTOR, false); set_param_z(PARAM_LINEAR_LOWER_LIMIT, 0); set_param_z(PARAM_LINEAR_UPPER_LIMIT, 0); set_param_z(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7); set_param_z(PARAM_LINEAR_RESTITUTION, 0.5); set_param_z(PARAM_LINEAR_DAMPING, 1.0); + set_param_z(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0); + set_param_z(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0); set_param_z(PARAM_ANGULAR_LOWER_LIMIT, 0); set_param_z(PARAM_ANGULAR_UPPER_LIMIT, 0); set_param_z(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f); @@ -964,4 +983,5 @@ Generic6DOFJoint::Generic6DOFJoint() { set_flag_z(FLAG_ENABLE_ANGULAR_LIMIT, true); set_flag_z(FLAG_ENABLE_LINEAR_LIMIT, true); set_flag_z(FLAG_ENABLE_MOTOR, false); + set_flag_z(FLAG_ENABLE_LINEAR_MOTOR, false); } diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h index 000109ac55..37870d6f30 100644 --- a/scene/3d/physics_joint.h +++ b/scene/3d/physics_joint.h @@ -249,6 +249,8 @@ public: PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, PARAM_LINEAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, PARAM_LINEAR_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, + PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY, + PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT, PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, @@ -265,6 +267,7 @@ public: FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, FLAG_ENABLE_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR, + FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR, FLAG_MAX = PhysicsServer::G6DOF_JOINT_FLAG_MAX }; diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp index f719a0356b..101d9ed70c 100644 --- a/scene/3d/proximity_group.cpp +++ b/scene/3d/proximity_group.cpp @@ -112,11 +112,6 @@ void ProximityGroup::_new_group(StringName p_name) { groups[p_name] = group_version; }; -void ProximityGroup::set_group_name(String p_group_name) { - - group_name = p_group_name; -}; - void ProximityGroup::_notification(int p_what) { switch (p_what) { @@ -153,9 +148,24 @@ void ProximityGroup::_proximity_group_broadcast(String p_name, Variant p_params) }; }; -void ProximityGroup::set_dispatch_mode(int p_mode) { +void ProximityGroup::set_group_name(const String &p_group_name) { + + group_name = p_group_name; +}; + +String ProximityGroup::get_group_name() const { - dispatch_mode = (DispatchMode)p_mode; + return group_name; +}; + +void ProximityGroup::set_dispatch_mode(DispatchMode p_mode) { + + dispatch_mode = p_mode; +}; + +ProximityGroup::DispatchMode ProximityGroup::get_dispatch_mode() const { + + return dispatch_mode; }; void ProximityGroup::set_grid_radius(const Vector3 &p_radius) { @@ -171,15 +181,22 @@ Vector3 ProximityGroup::get_grid_radius() const { void ProximityGroup::_bind_methods() { ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup::set_group_name); - ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup::broadcast); + ClassDB::bind_method(D_METHOD("get_group_name"), &ProximityGroup::get_group_name); ClassDB::bind_method(D_METHOD("set_dispatch_mode", "mode"), &ProximityGroup::set_dispatch_mode); - ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup::_proximity_group_broadcast); + ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup::get_dispatch_mode); ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup::set_grid_radius); ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup::get_grid_radius); + ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup::broadcast); + ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup::_proximity_group_broadcast); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius"); - ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::ARRAY, "parameters"))); + ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters"))); + + BIND_ENUM_CONSTANT(MODE_PROXY); + BIND_ENUM_CONSTANT(MODE_SIGNAL); }; ProximityGroup::ProximityGroup() { diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h index aae44e0be5..448f30bf80 100644 --- a/scene/3d/proximity_group.h +++ b/scene/3d/proximity_group.h @@ -67,15 +67,21 @@ public: static void _bind_methods(); public: - void set_group_name(String p_group_name); - void broadcast(String p_name, Variant p_params); - void set_dispatch_mode(int p_mode); + void set_group_name(const String &p_group_name); + String get_group_name() const; + + void set_dispatch_mode(DispatchMode p_mode); + DispatchMode get_dispatch_mode() const; void set_grid_radius(const Vector3 &p_radius); Vector3 get_grid_radius() const; + void broadcast(String p_name, Variant p_params); + ProximityGroup(); ~ProximityGroup(); }; +VARIANT_ENUM_CAST(ProximityGroup::DispatchMode); + #endif diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 556774a0d1..7f83e2c3ea 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -103,7 +103,7 @@ void RayCast::set_enabled(bool p_enabled) { enabled = p_enabled; if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) - set_physics_process(p_enabled); + set_physics_process_internal(p_enabled); if (!p_enabled) collided = false; @@ -150,12 +150,12 @@ void RayCast::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { if (enabled && !Engine::get_singleton()->is_editor_hint()) { - set_physics_process(true); + set_physics_process_internal(true); if (get_tree()->is_debugging_collisions_hint()) _update_debug_shape(); } else - set_physics_process(false); + set_physics_process_internal(false); if (Object::cast_to<CollisionObject>(get_parent())) { if (exclude_parent_body) @@ -168,14 +168,14 @@ void RayCast::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { if (enabled) { - set_physics_process(false); + set_physics_process_internal(false); } if (debug_shape) _clear_debug_shape(); } break; - case NOTIFICATION_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) break; @@ -217,6 +217,8 @@ void RayCast::_update_raycast_state() { against_shape = rr.shape; } else { collided = false; + against = 0; + against_shape = 0; } } diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index 9e3a9ac27f..2178da02b5 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -195,7 +195,7 @@ void ReflectionProbe::_validate_property(PropertyInfo &property) const { if (property.name == "interior/ambient_color" || property.name == "interior/ambient_energy" || property.name == "interior/ambient_contrib") { if (!interior) { - property.usage = PROPERTY_USAGE_NOEDITOR; + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; } } } diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp index 02768ac91f..d5bff676cb 100644 --- a/scene/3d/scenario_fx.cpp +++ b/scene/3d/scenario_fx.cpp @@ -79,7 +79,11 @@ Ref<Environment> WorldEnvironment::get_environment() const { String WorldEnvironment::get_configuration_warning() const { - if (/*!is_visible_in_tree() ||*/ !is_inside_tree() || !environment.is_valid()) + if (!environment.is_valid()) { + return TTR("WorldEnvironment needs an Environment resource."); + } + + if (/*!is_visible_in_tree() ||*/ !is_inside_tree()) return String(); List<Node *> nodes; @@ -89,6 +93,10 @@ String WorldEnvironment::get_configuration_warning() const { return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); } + if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) { + return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes)."); + } + return String(); } diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 99541db4d3..a7eb54c85d 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -33,6 +33,7 @@ #include "message_queue.h" #include "core/project_settings.h" +#include "scene/3d/physics_body.h" #include "scene/resources/surface_tool.h" bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { @@ -61,7 +62,7 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { set_bone_enabled(which, p_value); else if (what == "pose") set_bone_pose(which, p_value); - else if (what == "bound_childs") { + else if (what == "bound_children") { Array children = p_value; if (is_inside_tree()) { @@ -105,7 +106,7 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const { r_ret = is_bone_enabled(which); else if (what == "pose") r_ret = get_bone_pose(which); - else if (what == "bound_childs") { + else if (what == "bound_children") { Array children; for (const List<uint32_t>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) { @@ -134,7 +135,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest")); p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled")); p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_childs")); + p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children")); } } @@ -377,6 +378,17 @@ void Skeleton::unparent_bone_and_rest(int p_bone) { _make_dirty(); } +void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) { + ERR_FAIL_INDEX(p_bone, bones.size()); + bones[p_bone].ignore_animation = p_ignore; +} + +bool Skeleton::is_bone_ignore_animation(int p_bone) const { + + ERR_FAIL_INDEX_V(p_bone, bones.size(), false); + return bones[p_bone].ignore_animation; +} + void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) { ERR_FAIL_INDEX(p_bone, bones.size()); @@ -522,6 +534,103 @@ void Skeleton::localize_rests() { } } +void _notify_physical_bones_simulation(bool start, Node *p_node) { + + for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { + _notify_physical_bones_simulation(start, p_node->get_child(i)); + } + + PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); + if (pb) { + pb->set_simulate_physics(start); + } +} + +void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) { + ERR_FAIL_INDEX(p_bone, bones.size()); + ERR_FAIL_COND(bones[p_bone].physical_bone); + ERR_FAIL_COND(!p_physical_bone); + bones[p_bone].physical_bone = p_physical_bone; + + _rebuild_physical_bones_cache(); +} + +void Skeleton::unbind_physical_bone_from_bone(int p_bone) { + ERR_FAIL_INDEX(p_bone, bones.size()); + bones[p_bone].physical_bone = NULL; + + _rebuild_physical_bones_cache(); +} + +PhysicalBone *Skeleton::get_physical_bone(int p_bone) { + ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL); + + return bones[p_bone].physical_bone; +} + +PhysicalBone *Skeleton::get_physical_bone_parent(int p_bone) { + ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL); + + if (bones[p_bone].cache_parent_physical_bone) { + return bones[p_bone].cache_parent_physical_bone; + } + + return _get_physical_bone_parent(p_bone); +} + +PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) { + ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL); + + const int parent_bone = bones[p_bone].parent; + if (0 > parent_bone) { + return NULL; + } + + PhysicalBone *pb = bones[parent_bone].physical_bone; + if (pb) { + return pb; + } else { + return get_physical_bone_parent(parent_bone); + } +} + +void Skeleton::_rebuild_physical_bones_cache() { + const int b_size = bones.size(); + for (int i = 0; i < b_size; ++i) { + bones[i].cache_parent_physical_bone = _get_physical_bone_parent(i); + if (bones[i].physical_bone) + bones[i].physical_bone->_on_bone_parent_changed(); + } +} + +void Skeleton::physical_bones_simulation(bool start) { + _notify_physical_bones_simulation(start, this); +} + +void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) { + + for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { + _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception); + } + + CollisionObject *co = Object::cast_to<CollisionObject>(p_node); + if (co) { + if (p_add) { + PhysicsServer::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception); + } else { + PhysicsServer::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception); + } + } +} + +void Skeleton::physical_bones_add_collision_exception(RID p_exception) { + _physical_bones_add_remove_collision_exception(true, this, p_exception); +} + +void Skeleton::physical_bones_remove_collision_exception(RID p_exception) { + _physical_bones_add_remove_collision_exception(false, this, p_exception); +} + void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone); @@ -558,6 +667,10 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform); + ClassDB::bind_method(D_METHOD("physical_bones_simulation", "start"), &Skeleton::physical_bones_simulation); + ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception); + ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception); + BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); } diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index de0d4216d9..f0e71c8b4f 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -37,6 +37,8 @@ /** @author Juan Linietsky <reduzio@gmail.com> */ + +class PhysicalBone; class Skeleton : public Spatial { GDCLASS(Skeleton, Spatial); @@ -48,6 +50,8 @@ class Skeleton : public Spatial { bool enabled; int parent; + bool ignore_animation; + bool disable_rest; Transform rest; Transform rest_global_inverse; @@ -60,13 +64,19 @@ class Skeleton : public Spatial { Transform transform_final; + PhysicalBone *physical_bone; + PhysicalBone *cache_parent_physical_bone; + List<uint32_t> nodes_bound; Bone() { parent = -1; enabled = true; + ignore_animation = false; custom_pose_enable = false; disable_rest = false; + physical_bone = NULL; + cache_parent_physical_bone = NULL; } }; @@ -83,12 +93,12 @@ class Skeleton : public Spatial { Array _get_bound_child_nodes_to_bone(int p_bone) const { Array bound; - List<Node *> childs; - get_bound_child_nodes_to_bone(p_bone, &childs); + List<Node *> children; + get_bound_child_nodes_to_bone(p_bone, &children); - for (int i = 0; i < childs.size(); i++) { + for (int i = 0; i < children.size(); i++) { - bound.push_back(childs[i]); + bound.push_back(children[i]); } return bound; } @@ -118,6 +128,9 @@ public: void unparent_bone_and_rest(int p_bone); + void set_bone_ignore_animation(int p_bone, bool p_ignore); + bool is_bone_ignore_animation(int p_bone) const; + void set_bone_disable_rest(int p_bone, bool p_disable); bool is_bone_rest_disabled(int p_bone) const; @@ -149,6 +162,25 @@ public: void localize_rests(); // used for loaders and tools + // Physical bone API + + void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone); + void unbind_physical_bone_from_bone(int p_bone); + + PhysicalBone *get_physical_bone(int p_bone); + PhysicalBone *get_physical_bone_parent(int p_bone); + +private: + /// This is a slow API os it's cached + PhysicalBone *_get_physical_bone_parent(int p_bone); + void _rebuild_physical_bones_cache(); + +public: + void physical_bones_simulation(bool start); + void physical_bones_add_collision_exception(RID p_exception); + void physical_bones_remove_collision_exception(RID p_exception); + +public: Skeleton(); ~Skeleton(); }; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index b3740dba68..748aa8aad4 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -85,9 +85,7 @@ void Spatial::_notify_dirty() { } void Spatial::_update_local_transform() const { - data.local_transform.basis = Basis(); - data.local_transform.basis.scale(data.scale); - data.local_transform.basis.rotate(data.rotation); + data.local_transform.basis.set_euler_scale(data.rotation, data.scale); data.dirty &= ~DIRTY_LOCAL; } @@ -188,7 +186,9 @@ void Spatial::_notification(int p_what) { if (data.gizmo.is_valid()) { data.gizmo->create(); if (data.gizmo->can_draw()) { - data.gizmo->redraw(); + if (is_visible_in_tree()) { + data.gizmo->redraw(); + } } data.gizmo->transform(); } @@ -286,6 +286,16 @@ Transform Spatial::get_global_transform() const { return data.global_transform; } +#ifdef TOOLS_ENABLED +Transform Spatial::get_global_gizmo_transform() const { + return get_global_transform(); +} + +Transform Spatial::get_local_gizmo_transform() const { + return get_transform(); +} +#endif + Spatial *Spatial::get_parent_spatial() const { return data.parent; @@ -409,7 +419,9 @@ void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) { data.gizmo->create(); if (data.gizmo->can_draw()) { - data.gizmo->redraw(); + if (is_visible_in_tree()) { + data.gizmo->redraw(); + } } data.gizmo->transform(); } @@ -428,10 +440,9 @@ Ref<SpatialGizmo> Spatial::get_gizmo() const { #endif } -#ifdef TOOLS_ENABLED - void Spatial::_update_gizmo() { +#ifdef TOOLS_ENABLED if (!is_inside_world()) return; data.gizmo_dirty = false; @@ -443,8 +454,10 @@ void Spatial::_update_gizmo() { data.gizmo->clear(); } } +#endif } +#ifdef TOOLS_ENABLED void Spatial::set_disable_gizmo(bool p_enabled) { data.gizmo_disabled = p_enabled; @@ -724,9 +737,7 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel); ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world); -#ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo); -#endif ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo); ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Spatial::set_gizmo); @@ -788,7 +799,7 @@ void Spatial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); ADD_GROUP("Visibility", ""); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); - //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), "set_transform", "get_transform") ; + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo"); ADD_SIGNAL(MethodInfo("visibility_changed")); } diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 518bba9a51..a43bed3e4a 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -100,10 +100,8 @@ class Spatial : public Node { #endif } data; -#ifdef TOOLS_ENABLED void _update_gizmo(); -#endif void _notify_dirty(); void _propagate_transform_changed(Spatial *p_origin); @@ -147,6 +145,11 @@ public: Transform get_transform() const; Transform get_global_transform() const; +#ifdef TOOLS_ENABLED + virtual Transform get_global_gizmo_transform() const; + virtual Transform get_local_gizmo_transform() const; +#endif + void set_as_toplevel(bool p_enabled); bool is_set_as_toplevel() const; diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp index 75da3a7911..c547e76e30 100644 --- a/scene/3d/spatial_velocity_tracker.cpp +++ b/scene/3d/spatial_velocity_tracker.cpp @@ -125,6 +125,8 @@ void SpatialVelocityTracker::_bind_methods() { ClassDB::bind_method(D_METHOD("update_position", "position"), &SpatialVelocityTracker::update_position); ClassDB::bind_method(D_METHOD("get_tracked_linear_velocity"), &SpatialVelocityTracker::get_tracked_linear_velocity); ClassDB::bind_method(D_METHOD("reset", "position"), &SpatialVelocityTracker::reset); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "track_physics_step"), "set_track_physics_step", "is_tracking_physics_step"); } SpatialVelocityTracker::SpatialVelocityTracker() { diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index aeee51c4b2..b72665aa2b 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -524,7 +524,7 @@ void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) { //bilateral constraint between two dynamic objects void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, - PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse) { + PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence) { real_t normalLenSqr = normal.length_squared(); //ERR_FAIL_COND( normalLenSqr < real_t(1.1)); @@ -572,7 +572,7 @@ void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vec b2invmass); // FIXME: rel_vel assignment here is overwritten by the following assignment. - // What seemes to be intented in the next next assignment is: rel_vel = normal.dot(rel_vel); + // What seemes to be intended in the next next assignment is: rel_vel = normal.dot(rel_vel); // Investigate why. real_t rel_vel = jac.getRelativeVelocity( s->get_linear_velocity(), @@ -582,8 +582,12 @@ void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vec rel_vel = normal.dot(vel); - //TODO: move this into proper structure - real_t contactDamping = real_t(0.4); + // !BAS! We had this set to 0.4, in bullet its 0.2 + // real_t contactDamping = real_t(0.2); + + // !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based + // keeping in mind our anti roll factor + real_t contactDamping = s->get_step() / p_rollInfluence; #define ONLY_USE_LINEAR_MASS #ifdef ONLY_USE_LINEAR_MASS real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass); @@ -704,7 +708,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, - m_axle[i], m_sideImpulse[i]); + m_axle[i], m_sideImpulse[i], wheelInfo.m_rollInfluence); m_sideImpulse[i] *= sideFrictionStiffness2; } diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 7810a42e8a..1ac3693cc4 100644 --- a/scene/3d/vehicle_body.h +++ b/scene/3d/vehicle_body.h @@ -168,7 +168,7 @@ class VehicleBody : public RigidBody { btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse); }; - void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse); + void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence); real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint); void _update_friction(PhysicsDirectBodyState *s); diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp index a8818a06c3..9d6e4941f3 100644 --- a/scene/3d/visibility_notifier.cpp +++ b/scene/3d/visibility_notifier.cpp @@ -170,7 +170,7 @@ void VisibilityEnabler::_find_nodes(Node *p_node) { if (add) { - p_node->connect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed", varray(p_node), CONNECT_ONESHOT); + p_node->connect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed", varray(p_node), CONNECT_ONESHOT); nodes[p_node] = meta; _change_node_state(p_node, false); } @@ -208,7 +208,7 @@ void VisibilityEnabler::_notification(int p_what) { if (!visible) _change_node_state(E->key(), true); - E->key()->disconnect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed"); + E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed"); } nodes.clear(); @@ -240,7 +240,7 @@ void VisibilityEnabler::_node_removed(Node *p_node) { if (!visible) _change_node_state(p_node, true); - p_node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed"); + p_node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed"); nodes.erase(p_node); } diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index e1717a56f3..13700e0bd3 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -461,16 +461,16 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p } } - if (bake_cells[p_idx].childs[i] == CHILD_EMPTY) { + if (bake_cells[p_idx].children[i] == CHILD_EMPTY) { //sub cell must be created uint32_t child_idx = bake_cells.size(); - bake_cells[p_idx].childs[i] = child_idx; + bake_cells[p_idx].children[i] = child_idx; bake_cells.resize(bake_cells.size() + 1); bake_cells[child_idx].level = p_level + 1; } - _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); + _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); } } } @@ -700,7 +700,7 @@ void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int half = (1 << (cell_subdiv - 1)) >> (p_level + 1); for (int i = 0; i < 8; i++) { - uint32_t child = bake_cells[p_idx].childs[i]; + uint32_t child = bake_cells[p_idx].children[i]; if (child == CHILD_EMPTY) continue; @@ -809,7 +809,7 @@ uint32_t VoxelLightBaker::_find_cell_at_pos(const Cell *cells, int x, int y, int ofs_z += half; } - cell = bc->childs[child]; + cell = bc->children[child]; if (cell == CHILD_EMPTY) return CHILD_EMPTY; @@ -1257,7 +1257,7 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { for (int i = 0; i < 8; i++) { - uint32_t child = bake_cells[p_idx].childs[i]; + uint32_t child = bake_cells[p_idx].children[i]; if (child == CHILD_EMPTY) continue; @@ -1483,7 +1483,7 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector ofs_z += half; } - cell = bc->childs[child]; + cell = bc->children[child]; if (cell == CHILD_EMPTY) break; @@ -1766,7 +1766,7 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V ofs_z += half; } - cell = bc->childs[child]; + cell = bc->children[child]; if (unlikely(cell == CHILD_EMPTY)) break; @@ -1928,7 +1928,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if (lightmap_ptr[i * width + j].normal == Vector3()) - continue; //empty, dont write over it anyway + continue; //empty, don't write over it anyway float gauss_sum = gauss_kernel[0]; Vector3 accum = lightmap_ptr[i * width + j].pos * gauss_kernel[0]; for (int k = 1; k < 4; k++) { @@ -2191,7 +2191,7 @@ PoolVector<int> VoxelLightBaker::create_gi_probe_data() { for (int i = 0; i < bake_cells.size(); i++) { for (int j = 0; j < 8; j++) { - w32[ofs++] = bake_cells[i].childs[j]; + w32[ofs++] = bake_cells[i].children[j]; } { //albedo @@ -2275,7 +2275,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re for (int i = 0; i < 8; i++) { - uint32_t child = bake_cells[p_idx].childs[i]; + uint32_t child = bake_cells[p_idx].children[i]; if (child == CHILD_EMPTY || child >= max_original_cells) continue; @@ -2290,7 +2290,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re if (i & 4) aabb.position.z += aabb.size.z; - _debug_mesh(bake_cells[p_idx].childs[i], p_level + 1, aabb, p_multimesh, idx, p_mode); + _debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx, p_mode); } } } @@ -2338,9 +2338,9 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) { for (int k = 0; k < 3; k++) { if (i < 3) - face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); + face_points[j][(i + k) % 3] = v[k]; else - face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1); + face_points[3 - j][(i + k) % 3] = -v[k]; } } @@ -2423,7 +2423,7 @@ PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) { } for (int j = 0; j < 8; j++) { - uint32_t child = bake_cells[demap[i]].childs[j]; + uint32_t child = bake_cells[demap[i]].children[j]; octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; } } diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h index d270a26a2a..6a1f1253a3 100644 --- a/scene/3d/voxel_light_baker.h +++ b/scene/3d/voxel_light_baker.h @@ -60,7 +60,7 @@ private: struct Cell { - uint32_t childs[8]; + uint32_t children[8]; float albedo[3]; //albedo in RGB24 float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) float normal[3]; @@ -70,7 +70,7 @@ private: Cell() { for (int i = 0; i < 8; i++) { - childs[i] = CHILD_EMPTY; + children[i] = CHILD_EMPTY; } for (int i = 0; i < 3; i++) { |