diff options
Diffstat (limited to 'scene/3d')
40 files changed, 4131 insertions, 1861 deletions
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 6ea980ec97..40a1029201 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -243,7 +243,7 @@ void Area::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->key(), node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape); } - emit_signal(SceneStringNames::get_singleton()->body_exited, obj); + emit_signal(SceneStringNames::get_singleton()->body_exited, 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); @@ -699,10 +699,10 @@ void Area::_bind_methods() { ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area::set_reverb_uniformity); ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area::get_reverb_uniformity); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index e7b3645001..8504a18f54 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -35,11 +35,8 @@ #include "scene/main/viewport.h" void AudioStreamPlayer3D::_mix_audio() { - if (!stream_playback.is_valid()) { - return; - } - - if (!active) { + if (!stream_playback.is_valid() || !active || + (stream_paused && !stream_paused_fade_out)) { return; } @@ -54,8 +51,13 @@ void AudioStreamPlayer3D::_mix_audio() { AudioFrame *buffer = mix_buffer.ptrw(); int buffer_size = mix_buffer.size(); - //mix - if (output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) { + if (stream_paused_fade_out) { + // Short fadeout ramp + buffer_size = MIN(buffer_size, 128); + } + + // Mix if we're not paused or we're fading out + if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) { float output_pitch_scale = 0.0; if (output_count) { @@ -105,8 +107,10 @@ void AudioStreamPlayer3D::_mix_audio() { int buffers = AudioServer::get_singleton()->get_channel_count(); for (int k = 0; k < buffers; k++) { - AudioFrame vol_inc = (current.vol[k] - prev_outputs[i].vol[k]) / float(buffer_size); - AudioFrame vol = current.vol[k]; + AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k]; + AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k]; + AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size); + AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k]; AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k); @@ -188,6 +192,8 @@ void AudioStreamPlayer3D::_mix_audio() { } output_ready = false; + stream_paused_fade_in = false; + stream_paused_fade_out = false; } float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { @@ -237,6 +243,18 @@ void AudioStreamPlayer3D::_notification(int p_what) { AudioServer::get_singleton()->remove_callback(_mix_audios, this); } + + if (p_what == NOTIFICATION_PAUSED) { + if (!can_process()) { + // Node can't process so we start fading out to silence + set_stream_paused(true); + } + } + + if (p_what == NOTIFICATION_UNPAUSED) { + set_stream_paused(false); + } + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { @@ -552,7 +570,6 @@ void AudioStreamPlayer3D::_notification(int p_what) { void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) { - ERR_FAIL_COND(!p_stream.is_valid()); AudioServer::get_singleton()->lock(); mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size()); @@ -564,14 +581,15 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) { setseek = -1; } - stream = p_stream; - stream_playback = p_stream->instance_playback(); + if (p_stream.is_valid()) { + stream = p_stream; + stream_playback = p_stream->instance_playback(); + } AudioServer::get_singleton()->unlock(); - if (stream_playback.is_null()) { + if (p_stream.is_valid() && stream_playback.is_null()) { stream.unref(); - ERR_FAIL_COND(stream_playback.is_null()); } } @@ -608,6 +626,7 @@ float AudioStreamPlayer3D::get_max_db() const { } void AudioStreamPlayer3D::set_pitch_scale(float p_pitch_scale) { + ERR_FAIL_COND(p_pitch_scale <= 0.0); pitch_scale = p_pitch_scale; } float AudioStreamPlayer3D::get_pitch_scale() const { @@ -825,6 +844,20 @@ AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking() return doppler_tracking; } +void AudioStreamPlayer3D::set_stream_paused(bool p_pause) { + + if (p_pause != stream_paused) { + stream_paused = p_pause; + stream_paused_fade_in = stream_paused ? false : true; + stream_paused_fade_out = stream_paused ? true : false; + } +} + +bool AudioStreamPlayer3D::get_stream_paused() const { + + return stream_paused; +} + void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream); @@ -888,6 +921,9 @@ void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &AudioStreamPlayer3D::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &AudioStreamPlayer3D::get_doppler_tracking); + ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused); + ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused); + ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); @@ -898,6 +934,7 @@ void AudioStreamPlayer3D::_bind_methods() { 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::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); @@ -949,9 +986,13 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() { attenuation_filter_db = -24; out_of_range_mode = OUT_OF_RANGE_MIX; doppler_tracking = DOPPLER_TRACKING_DISABLED; + stream_paused = false; + stream_paused_fade_in = false; + stream_paused_fade_out = false; velocity_tracker.instance(); AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); + set_disable_scale(true); } AudioStreamPlayer3D::~AudioStreamPlayer3D() { } diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 1fcb83cf21..14413d0702 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -108,6 +108,9 @@ private: float max_db; float pitch_scale; bool autoplay; + bool stream_paused; + bool stream_paused_fade_in; + bool stream_paused_fade_out; StringName bus; void _mix_audio(); @@ -199,6 +202,9 @@ public: void set_doppler_tracking(DopplerTracking p_tracking); DopplerTracking get_doppler_tracking() const; + void set_stream_paused(bool p_pause); + bool get_stream_paused() const; + AudioStreamPlayer3D(); ~AudioStreamPlayer3D(); }; diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 204aaef7ec..2cb59c871c 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -374,9 +374,6 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi capture_subdiv--; css *= 2.0; } - - print_line("bake subdiv: " + itos(bake_subdiv)); - print_line("capture subdiv: " + itos(capture_subdiv)); } baker.begin_bake(bake_subdiv, bake_bounds); @@ -811,4 +808,5 @@ BakedLightmap::BakedLightmap() { propagation = 1; hdr = false; image_path = "."; + set_disable_scale(true); } diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index e11e8abe5b..a4582b7d7d 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -31,9 +31,10 @@ #include "camera.h" #include "camera_matrix.h" +#include "collision_object.h" +#include "engine.h" #include "scene/resources/material.h" #include "scene/resources/surface_tool.h" - void Camera::_update_audio_listener_state() { } @@ -74,10 +75,7 @@ void Camera::_update_camera() { if (!is_inside_tree()) return; - Transform tr = get_camera_transform(); - tr.origin += tr.basis.get_axis(1) * v_offset; - tr.origin += tr.basis.get_axis(0) * h_offset; - VisualServer::get_singleton()->camera_set_transform(camera, tr); + VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform()); // here goes listener stuff /* @@ -143,7 +141,10 @@ void Camera::_notification(int p_what) { Transform Camera::get_camera_transform() const { - return get_global_transform().orthonormalized(); + Transform tr = get_global_transform().orthonormalized(); + tr.origin += tr.basis.get_axis(1) * v_offset; + tr.origin += tr.basis.get_axis(0) * h_offset; + return tr; } void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { @@ -313,6 +314,32 @@ bool Camera::is_position_behind(const Vector3 &p_pos) const { return eyedir.dot(p_pos) < (eyedir.dot(t.origin) + near); } +Vector<Vector3> Camera::get_near_plane_points() const { + if (!is_inside_tree()) { + ERR_EXPLAIN("Camera is not inside scene."); + ERR_FAIL_COND_V(!is_inside_tree(), Vector<Vector3>()); + } + + Size2 viewport_size = get_viewport()->get_visible_rect().size; + + CameraMatrix cm; + + if (mode == PROJECTION_ORTHOGONAL) + cm.set_orthogonal(size, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); + else + cm.set_perspective(fov, viewport_size.aspect(), near, far, keep_aspect == KEEP_WIDTH); + + Vector3 endpoints[8]; + cm.get_endpoints(Transform(), endpoints); + + Vector<Vector3> points; + points.push_back(Vector3()); + for (int i = 0; i < 4; i++) { + points.push_back(endpoints[i + 4]); + } + return points; +} + Point2 Camera::unproject_position(const Vector3 &p_pos) const { if (!is_inside_tree()) { @@ -468,6 +495,10 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking); + + ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera::set_cull_mask_bit); + ClassDB::bind_method(D_METHOD("get_cull_mask_bit", "layer"), &Camera::get_cull_mask_bit); + //ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current ); ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode"); @@ -480,7 +511,7 @@ void Camera::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_znear", "get_znear"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01,or_greater"), "set_znear", "get_znear"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); @@ -550,6 +581,20 @@ uint32_t Camera::get_cull_mask() const { return layers; } +void Camera::set_cull_mask_bit(int p_layer, bool p_enable) { + ERR_FAIL_INDEX(p_layer, 32); + if (p_enable) { + set_cull_mask(layers | (1 << p_layer)); + } else { + set_cull_mask(layers & (~(1 << p_layer))); + } +} + +bool Camera::get_cull_mask_bit(int p_layer) const { + ERR_FAIL_INDEX_V(p_layer, 32, false); + return (layers & (1 << p_layer)); +} + Vector<Plane> Camera::get_frustum() const { ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>()); @@ -613,9 +658,231 @@ Camera::Camera() { velocity_tracker.instance(); doppler_tracking = DOPPLER_TRACKING_DISABLED; set_notify_transform(true); + set_disable_scale(true); } Camera::~Camera() { VisualServer::get_singleton()->free(camera); } + +//////////////////////////////////////// + +void ClippedCamera::set_margin(float p_margin) { + margin = p_margin; +} +float ClippedCamera::get_margin() const { + return margin; +} +void ClippedCamera::set_process_mode(ProcessMode p_mode) { + + if (process_mode == p_mode) { + return; + } + set_process_internal(p_mode == CLIP_PROCESS_IDLE); + set_physics_process_internal(p_mode == CLIP_PROCESS_PHYSICS); +} +ClippedCamera::ProcessMode ClippedCamera::get_process_mode() const { + return process_mode; +} + +Transform ClippedCamera::get_camera_transform() const { + + Transform t = Camera::get_camera_transform(); + t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset; + return t; +} + +void ClippedCamera::_notification(int p_what) { + if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { + + Spatial *parent = Object::cast_to<Spatial>(get_parent()); + if (!parent) { + return; + } + + PhysicsDirectSpaceState *dspace = get_world()->get_direct_space_state(); + ERR_FAIL_COND(!dspace); // most likely physics set to threads + + Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized(); + Vector3 cam_pos = get_global_transform().origin; + Vector3 parent_pos = parent->get_global_transform().origin; + + Plane parent_plane(parent_pos, cam_fw); + + if (parent_plane.is_point_over(cam_pos)) { + //cam is beyond parent plane + return; + } + + Vector3 ray_from = parent_plane.project(cam_pos); + + clip_offset = 0; //reset by defau;t + + { //check if points changed + Vector<Vector3> local_points = get_near_plane_points(); + + bool all_equal = true; + + for (int i = 0; i < 5; i++) { + if (points[i] != local_points[i]) { + all_equal = false; + break; + } + } + + if (!all_equal) { + PhysicsServer::get_singleton()->shape_set_data(pyramid_shape, local_points); + points = local_points; + } + } + + Transform xf = get_global_transform(); + xf.origin = ray_from; + xf.orthonormalize(); + + float csafe, cunsafe; + if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, csafe, cunsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) { + clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from).normalized() * csafe); + } + + _update_camera(); + } + + if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { + update_gizmo(); + } +} + +void ClippedCamera::set_collision_mask(uint32_t p_mask) { + + collision_mask = p_mask; +} + +uint32_t ClippedCamera::get_collision_mask() const { + + return collision_mask; +} + +void ClippedCamera::set_collision_mask_bit(int p_bit, bool p_value) { + + uint32_t mask = get_collision_mask(); + if (p_value) + mask |= 1 << p_bit; + else + mask &= ~(1 << p_bit); + set_collision_mask(mask); +} + +bool ClippedCamera::get_collision_mask_bit(int p_bit) const { + + return get_collision_mask() & (1 << p_bit); +} + +void ClippedCamera::add_exception_rid(const RID &p_rid) { + + exclude.insert(p_rid); +} + +void ClippedCamera::add_exception(const Object *p_object) { + + ERR_FAIL_NULL(p_object); + const CollisionObject *co = Object::cast_to<CollisionObject>(p_object); + if (!co) + return; + add_exception_rid(co->get_rid()); +} + +void ClippedCamera::remove_exception_rid(const RID &p_rid) { + + exclude.erase(p_rid); +} + +void ClippedCamera::remove_exception(const Object *p_object) { + + ERR_FAIL_NULL(p_object); + const CollisionObject *co = Object::cast_to<CollisionObject>(p_object); + if (!co) + return; + remove_exception_rid(co->get_rid()); +} + +void ClippedCamera::clear_exceptions() { + + exclude.clear(); +} + +void ClippedCamera::set_clip_to_areas(bool p_clip) { + + clip_to_areas = p_clip; +} + +bool ClippedCamera::is_clip_to_areas_enabled() const { + + return clip_to_areas; +} + +void ClippedCamera::set_clip_to_bodies(bool p_clip) { + + clip_to_bodies = p_clip; +} + +bool ClippedCamera::is_clip_to_bodies_enabled() const { + + return clip_to_bodies; +} + +void ClippedCamera::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera::set_margin); + ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera::get_margin); + + ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera::set_process_mode); + ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera::get_process_mode); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &ClippedCamera::set_collision_mask_bit); + ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &ClippedCamera::get_collision_mask_bit); + + ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera::add_exception_rid); + ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera::add_exception); + + ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera::remove_exception_rid); + ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera::remove_exception); + + ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera::set_clip_to_areas); + ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera::is_clip_to_areas_enabled); + + ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera::set_clip_to_bodies); + ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera::is_clip_to_bodies_enabled); + + ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera::clear_exceptions); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ADD_GROUP("Clip To", "clip_to"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled"); + + BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS); + BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE); +} +ClippedCamera::ClippedCamera() { + margin = 0; + clip_offset = 0; + process_mode = CLIP_PROCESS_PHYSICS; + set_physics_process_internal(true); + collision_mask = 1; + set_notify_local_transform(Engine::get_singleton()->is_editor_hint()); + points.resize(5); + pyramid_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CONVEX_POLYGON); + clip_to_areas = false; + clip_to_bodies = true; +} +ClippedCamera::~ClippedCamera() { + PhysicsServer::get_singleton()->free(pyramid_shape); +} diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 1b506e0c4f..a35c9d6e7f 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -139,9 +139,14 @@ public: bool is_position_behind(const Vector3 &p_pos) const; virtual Vector3 project_position(const Point2 &p_point) const; + Vector<Vector3> get_near_plane_points() const; + void set_cull_mask(uint32_t p_layers); uint32_t get_cull_mask() const; + void set_cull_mask_bit(int p_layer, bool p_enable); + bool get_cull_mask_bit(int p_layer) const; + virtual Vector<Plane> get_frustum() const; void set_environment(const Ref<Environment> &p_environment); @@ -169,4 +174,62 @@ VARIANT_ENUM_CAST(Camera::Projection); VARIANT_ENUM_CAST(Camera::KeepAspect); VARIANT_ENUM_CAST(Camera::DopplerTracking); +class ClippedCamera : public Camera { + + GDCLASS(ClippedCamera, Camera); + +public: + enum ProcessMode { + CLIP_PROCESS_PHYSICS, + CLIP_PROCESS_IDLE, + }; + +private: + ProcessMode process_mode; + RID pyramid_shape; + float margin; + float clip_offset; + uint32_t collision_mask; + bool clip_to_areas; + bool clip_to_bodies; + + Set<RID> exclude; + + Vector<Vector3> points; + +protected: + void _notification(int p_what); + static void _bind_methods(); + virtual Transform get_camera_transform() const; + +public: + void set_clip_to_areas(bool p_clip); + bool is_clip_to_areas_enabled() const; + + void set_clip_to_bodies(bool p_clip); + bool is_clip_to_bodies_enabled() const; + + void set_margin(float p_margin); + float get_margin() const; + + void set_process_mode(ProcessMode p_mode); + ProcessMode get_process_mode() const; + + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + + void add_exception_rid(const RID &p_rid); + void add_exception(const Object *p_object); + void remove_exception_rid(const RID &p_rid); + void remove_exception(const Object *p_object); + void clear_exceptions(); + + ClippedCamera(); + ~ClippedCamera(); +}; + +VARIANT_ENUM_CAST(ClippedCamera::ProcessMode); #endif diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 1d5d1b2afe..99b8ce0567 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -148,7 +148,7 @@ void CollisionObject::_bind_methods() { BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); - ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); + ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); ADD_SIGNAL(MethodInfo("mouse_entered")); ADD_SIGNAL(MethodInfo("mouse_exited")); @@ -305,7 +305,7 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { for (int i = 0; i < E->get().shapes.size(); i++) { if (E->get().shapes[i].index > index_to_remove) { - E->get().shapes[i].index -= 1; + E->get().shapes.write[i].index -= 1; } } } diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index f31d65e411..f8ef04b78f 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -39,6 +39,7 @@ class CollisionObject : public Spatial { GDCLASS(CollisionObject, Spatial); bool area; + RID rid; struct ShapeData { diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h index c9c91a5824..6ca8e80ea1 100644 --- a/scene/3d/collision_shape.h +++ b/scene/3d/collision_shape.h @@ -49,6 +49,7 @@ class CollisionShape : public Spatial { void resource_changed(RES res); bool disabled; +protected: void _create_debug_shape(); void _update_in_shape_owner(bool p_xform_only = false); diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp new file mode 100644 index 0000000000..712f0ba78b --- /dev/null +++ b/scene/3d/cpu_particles.cpp @@ -0,0 +1,1444 @@ +/*************************************************************************/ +/* cpu_particles.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "cpu_particles.h" + +#include "scene/3d/camera.h" +#include "scene/3d/particles.h" +#include "scene/resources/particles_material.h" +#include "servers/visual_server.h" + +AABB CPUParticles::get_aabb() const { + + return AABB(); +} +PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const { + + return PoolVector<Face3>(); +} + +void CPUParticles::set_emitting(bool p_emitting) { + + emitting = p_emitting; + if (!is_processing_internal()) { + set_process_internal(true); + if (is_inside_tree()) { +#ifndef NO_THREADS + update_mutex->lock(); +#endif + VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); + +#ifndef NO_THREADS + update_mutex->unlock(); +#endif + } + } +} + +void CPUParticles::set_amount(int p_amount) { + + ERR_FAIL_COND(p_amount < 1); + + particles.resize(p_amount); + { + PoolVector<Particle>::Write w = particles.write(); + + for (int i = 0; i < p_amount; i++) { + w[i].active = false; + } + } + + particle_data.resize((12 + 4 + 1) * p_amount); + VS::get_singleton()->multimesh_allocate(multimesh, p_amount, VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_8BIT, VS::MULTIMESH_CUSTOM_DATA_FLOAT); + + particle_order.resize(p_amount); +} +void CPUParticles::set_lifetime(float p_lifetime) { + + ERR_FAIL_COND(p_lifetime <= 0); + lifetime = p_lifetime; +} + +void CPUParticles::set_one_shot(bool p_one_shot) { + + one_shot = p_one_shot; +} + +void CPUParticles::set_pre_process_time(float p_time) { + + pre_process_time = p_time; +} +void CPUParticles::set_explosiveness_ratio(float p_ratio) { + + explosiveness_ratio = p_ratio; +} +void CPUParticles::set_randomness_ratio(float p_ratio) { + + randomness_ratio = p_ratio; +} +void CPUParticles::set_use_local_coordinates(bool p_enable) { + + local_coords = p_enable; +} +void CPUParticles::set_speed_scale(float p_scale) { + + speed_scale = p_scale; +} + +bool CPUParticles::is_emitting() const { + + return emitting; +} +int CPUParticles::get_amount() const { + + return particles.size(); +} +float CPUParticles::get_lifetime() const { + + return lifetime; +} +bool CPUParticles::get_one_shot() const { + + return one_shot; +} + +float CPUParticles::get_pre_process_time() const { + + return pre_process_time; +} +float CPUParticles::get_explosiveness_ratio() const { + + return explosiveness_ratio; +} +float CPUParticles::get_randomness_ratio() const { + + return randomness_ratio; +} + +bool CPUParticles::get_use_local_coordinates() const { + + return local_coords; +} + +float CPUParticles::get_speed_scale() const { + + return speed_scale; +} + +void CPUParticles::set_draw_order(DrawOrder p_order) { + + draw_order = p_order; +} + +CPUParticles::DrawOrder CPUParticles::get_draw_order() const { + + return draw_order; +} + +void CPUParticles::set_mesh(const Ref<Mesh> &p_mesh) { + + mesh = p_mesh; + if (mesh.is_valid()) { + VS::get_singleton()->multimesh_set_mesh(multimesh, mesh->get_rid()); + } else { + VS::get_singleton()->multimesh_set_mesh(multimesh, RID()); + } +} + +Ref<Mesh> CPUParticles::get_mesh() const { + + return mesh; +} + +void CPUParticles::set_fixed_fps(int p_count) { + fixed_fps = p_count; +} + +int CPUParticles::get_fixed_fps() const { + return fixed_fps; +} + +void CPUParticles::set_fractional_delta(bool p_enable) { + fractional_delta = p_enable; +} + +bool CPUParticles::get_fractional_delta() const { + return fractional_delta; +} + +String CPUParticles::get_configuration_warning() const { + + String warnings; + + return warnings; +} + +void CPUParticles::restart() { + + time = 0; + inactive_time = 0; + frame_remainder = 0; + cycle = 0; + + { + int pc = particles.size(); + PoolVector<Particle>::Write w = particles.write(); + + for (int i = 0; i < pc; i++) { + w[i].active = false; + } + } +} + +void CPUParticles::set_spread(float p_spread) { + + spread = p_spread; +} + +float CPUParticles::get_spread() const { + + return spread; +} + +void CPUParticles::set_flatness(float p_flatness) { + + flatness = p_flatness; +} +float CPUParticles::get_flatness() const { + + return flatness; +} + +void CPUParticles::set_param(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + parameters[p_param] = p_value; +} +float CPUParticles::get_param(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + + return parameters[p_param]; +} + +void CPUParticles::set_param_randomness(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + randomness[p_param] = p_value; +} +float CPUParticles::get_param_randomness(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); + + return randomness[p_param]; +} + +static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) { + + Ref<Curve> curve = p_curve; + if (!curve.is_valid()) + return; + + curve->ensure_default_setup(p_min, p_max); +} + +void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) { + + ERR_FAIL_INDEX(p_param, PARAM_MAX); + + curve_parameters[p_param] = p_curve; + + switch (p_param) { + case PARAM_INITIAL_LINEAR_VELOCITY: { + //do none for this one + } break; + case PARAM_ANGULAR_VELOCITY: { + _adjust_curve_range(p_curve, -360, 360); + } break; + /*case PARAM_ORBIT_VELOCITY: { + _adjust_curve_range(p_curve, -500, 500); + } break;*/ + case PARAM_LINEAR_ACCEL: { + _adjust_curve_range(p_curve, -200, 200); + } break; + case PARAM_RADIAL_ACCEL: { + _adjust_curve_range(p_curve, -200, 200); + } break; + case PARAM_TANGENTIAL_ACCEL: { + _adjust_curve_range(p_curve, -200, 200); + } break; + case PARAM_DAMPING: { + _adjust_curve_range(p_curve, 0, 100); + } break; + case PARAM_ANGLE: { + _adjust_curve_range(p_curve, -360, 360); + } break; + case PARAM_SCALE: { + + } break; + case PARAM_HUE_VARIATION: { + _adjust_curve_range(p_curve, -1, 1); + } break; + case PARAM_ANIM_SPEED: { + _adjust_curve_range(p_curve, 0, 200); + } break; + case PARAM_ANIM_OFFSET: { + } break; + default: {} + } +} +Ref<Curve> CPUParticles::get_param_curve(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Curve>()); + + return curve_parameters[p_param]; +} + +void CPUParticles::set_color(const Color &p_color) { + + color = p_color; +} + +Color CPUParticles::get_color() const { + + return color; +} + +void CPUParticles::set_color_ramp(const Ref<Gradient> &p_ramp) { + + color_ramp = p_ramp; +} + +Ref<Gradient> CPUParticles::get_color_ramp() const { + + return color_ramp; +} + +void CPUParticles::set_particle_flag(Flags p_flag, bool p_enable) { + ERR_FAIL_INDEX(p_flag, FLAG_MAX); + flags[p_flag] = p_enable; + if (p_flag == FLAG_DISABLE_Z) { + _change_notify(); + } +} + +bool CPUParticles::get_particle_flag(Flags p_flag) const { + ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); + return flags[p_flag]; +} + +void CPUParticles::set_emission_shape(EmissionShape p_shape) { + + emission_shape = p_shape; +} + +void CPUParticles::set_emission_sphere_radius(float p_radius) { + + emission_sphere_radius = p_radius; +} + +void CPUParticles::set_emission_box_extents(Vector3 p_extents) { + + emission_box_extents = p_extents; +} + +void CPUParticles::set_emission_points(const PoolVector<Vector3> &p_points) { + + emission_points = p_points; +} + +void CPUParticles::set_emission_normals(const PoolVector<Vector3> &p_normals) { + + emission_normals = p_normals; +} + +void CPUParticles::set_emission_colors(const PoolVector<Color> &p_colors) { + + emission_colors = p_colors; +} + +float CPUParticles::get_emission_sphere_radius() const { + + return emission_sphere_radius; +} +Vector3 CPUParticles::get_emission_box_extents() const { + + return emission_box_extents; +} +PoolVector<Vector3> CPUParticles::get_emission_points() const { + + return emission_points; +} +PoolVector<Vector3> CPUParticles::get_emission_normals() const { + + return emission_normals; +} + +PoolVector<Color> CPUParticles::get_emission_colors() const { + + return emission_colors; +} + +CPUParticles::EmissionShape CPUParticles::get_emission_shape() const { + return emission_shape; +} +void CPUParticles::set_gravity(const Vector3 &p_gravity) { + + gravity = p_gravity; +} + +Vector3 CPUParticles::get_gravity() const { + + return gravity; +} + +void CPUParticles::_validate_property(PropertyInfo &property) const { + + if (property.name == "color" && color_ramp.is_valid()) { + property.usage = 0; + } + + if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { + property.usage = 0; + } + + if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { + property.usage = 0; + } + + if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { + property.usage = 0; + } + + if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + property.usage = 0; + } + /* + if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { + property.usage = 0; + } + */ +} + +static uint32_t idhash(uint32_t x) { + + x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b); + x = ((x >> uint32_t(16)) ^ x) * uint32_t(0x45d9f3b); + x = (x >> uint32_t(16)) ^ x; + return x; +} + +static float rand_from_seed(uint32_t &seed) { + int k; + int s = int(seed); + if (s == 0) + s = 305420679; + k = s / 127773; + s = 16807 * (s - k * 127773) - 2836 * k; + if (s < 0) + s += 2147483647; + seed = uint32_t(s); + return float(seed % uint32_t(65536)) / 65535.0; +} + +static float rand_from_seed_m1_p1(uint32_t &seed) { + return rand_from_seed(seed) * 2.0 - 1.0; +} + +void CPUParticles::_particles_process(float p_delta) { + + p_delta *= speed_scale; + + int pcount = particles.size(); + PoolVector<Particle>::Write w = particles.write(); + + Particle *parray = w.ptr(); + + float prev_time = time; + time += p_delta; + if (time > lifetime) { + time = Math::fmod(time, lifetime); + cycle++; + if (one_shot && cycle > 0) { + emitting = false; + } + } + + Transform emission_xform; + Basis velocity_xform; + if (!local_coords) { + emission_xform = get_global_transform(); + velocity_xform = emission_xform.basis.inverse().transposed(); + } + + for (int i = 0; i < pcount; i++) { + + Particle &p = parray[i]; + + if (!emitting && !p.active) + continue; + + float restart_time = (float(i) / float(pcount)) * lifetime; + float local_delta = p_delta; + + if (randomness_ratio > 0.0) { + uint32_t seed = cycle; + if (restart_time >= time) { + seed -= uint32_t(1); + } + seed *= uint32_t(pcount); + seed += uint32_t(i); + float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; + restart_time += randomness_ratio * random * 1.0 / float(pcount); + } + + restart_time *= (1.0 - explosiveness_ratio); + bool restart = false; + + if (time > prev_time) { + // restart_time >= prev_time is used so particles emit in the first frame they are processed + + if (restart_time >= prev_time && restart_time < time) { + restart = true; + if (fractional_delta) { + local_delta = (time - restart_time) * lifetime; + } + } + + } else if (local_delta > 0.0) { + if (restart_time >= prev_time) { + restart = true; + if (fractional_delta) { + local_delta = (1.0 - restart_time + time) * lifetime; + } + + } else if (restart_time < time) { + restart = true; + if (fractional_delta) { + local_delta = (time - restart_time) * lifetime; + } + } + } + + if (restart) { + + if (!emitting) { + p.active = false; + continue; + } + p.active = true; + + /*float tex_linear_velocity = 0; + if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0); + }*/ + + float tex_angle = 0.0; + if (curve_parameters[PARAM_ANGLE].is_valid()) { + tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0); + } + + float tex_anim_offset = 0.0; + if (curve_parameters[PARAM_ANGLE].is_valid()) { + tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0); + } + + p.seed = Math::rand(); + + p.angle_rand = Math::randf(); + p.scale_rand = Math::randf(); + p.hue_rot_rand = Math::randf(); + p.anim_offset_rand = Math::randf(); + + float angle1_rad; + float angle2_rad; + + if (flags[FLAG_DISABLE_Z]) { + + angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; + Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); + p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); + + } else { + //initiate velocity spread in 3D + angle1_rad = (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; + angle2_rad = (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0; + + Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad)); + Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad)); + direction_yz.z = direction_yz.z / Math::sqrt(direction_yz.z); //better uniform distribution + Vector3 direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z); + direction.normalize(); + p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); + } + + float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]); + p.custom[0] = Math::deg2rad(base_angle); //angle + p.custom[1] = 0.0; //phase + p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1) + p.transform = Transform(); + p.time = 0; + p.base_color = Color(1, 1, 1, 1); + + switch (emission_shape) { + case EMISSION_SHAPE_POINT: { + //do none + } break; + case EMISSION_SHAPE_SPHERE: { + p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius; + } break; + case EMISSION_SHAPE_BOX: { + p.transform.origin = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_box_extents; + } break; + case EMISSION_SHAPE_POINTS: + case EMISSION_SHAPE_DIRECTED_POINTS: { + + int pc = emission_points.size(); + if (pc == 0) + break; + + int random_idx = Math::rand() % pc; + + p.transform.origin = emission_points.get(random_idx); + + if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) { + if (flags[FLAG_DISABLE_Z]) { + /* + mat2 rotm; + "; + rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy; + rotm[1] = rotm[0].yx * vec2(1.0, -1.0); + VELOCITY.xy = rotm * VELOCITY.xy; + */ + } else { + Vector3 normal = emission_normals.get(random_idx); + Vector3 v0 = Math::abs(normal.z) < 0.999 ? Vector3(0.0, 0.0, 1.0) : Vector3(0, 1.0, 0.0); + Vector3 tangent = v0.cross(normal).normalized(); + Vector3 bitangent = tangent.cross(normal).normalized(); + Basis m3; + m3.set_axis(0, tangent); + m3.set_axis(1, bitangent); + m3.set_axis(2, normal); + p.velocity = m3.xform(p.velocity); + } + } + + if (emission_colors.size() == pc) { + p.base_color = emission_colors.get(random_idx); + } + } break; + } + + if (!local_coords) { + p.velocity = velocity_xform.xform(p.velocity); + p.transform = emission_xform * p.transform; + } + + if (flags[FLAG_DISABLE_Z]) { + p.velocity.z = 0.0; + p.velocity.z = 0.0; + } + + } else if (!p.active) { + continue; + } else { + + uint32_t alt_seed = p.seed; + + p.time += local_delta; + p.custom[1] = p.time / lifetime; + + float tex_linear_velocity = 0.0; + if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); + } + /* + float tex_orbit_velocity = 0.0; + + if (flags[FLAG_DISABLE_Z]) { + + if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) { + tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]); + } + } +*/ + float tex_angular_velocity = 0.0; + if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { + tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); + } + + float tex_linear_accel = 0.0; + if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { + tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]); + } + + float tex_tangential_accel = 0.0; + if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { + tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]); + } + + float tex_radial_accel = 0.0; + if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { + tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]); + } + + float tex_damping = 0.0; + if (curve_parameters[PARAM_DAMPING].is_valid()) { + tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]); + } + + float tex_angle = 0.0; + if (curve_parameters[PARAM_ANGLE].is_valid()) { + tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]); + } + float tex_anim_speed = 0.0; + if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { + tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]); + } + + float tex_anim_offset = 0.0; + if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { + tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]); + } + + Vector3 force = gravity; + Vector3 pos = p.transform.origin; + if (flags[FLAG_DISABLE_Z]) { + pos.z = 0.0; + } + //apply linear acceleration + force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3(); + //apply radial acceleration + Vector3 org = emission_xform.origin; + Vector3 diff = pos - org; + force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3(); + //apply tangential acceleration; + if (flags[FLAG_DISABLE_Z]) { + + Vector3 yx = Vector3(diff.y, 0, diff.x); + force += yx.length() > 0.0 ? (yx * Vector3(-1.0, 0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); + + } else { + Vector3 crossDiff = diff.normalized().cross(gravity.normalized()); + force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); + } + //apply attractor forces + p.velocity += force * local_delta; + //orbit velocity +#if 0 + if (flags[FLAG_DISABLE_Z]) { + + float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random); + if (orbit_amount != 0.0) { + float ang = orbit_amount * DELTA * pi * 2.0; + mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang))); + TRANSFORM[3].xy -= diff.xy; + TRANSFORM[3].xy += rot * diff.xy; + } + } +#endif + if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { + p.velocity = p.velocity.normalized() * tex_linear_velocity; + } + if (parameters[PARAM_DAMPING] + tex_damping > 0.0) { + + float v = p.velocity.length(); + float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]); + v -= damp * local_delta; + if (v < 0.0) { + p.velocity = Vector3(); + } else { + p.velocity = p.velocity.normalized() * v; + } + } + float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]); + base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]); + p.custom[0] = Math::deg2rad(base_angle); //angle + p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle + if (flags[FLAG_ANIM_LOOP]) { + p.custom[2] = Math::fmod(p.custom[2], 1.0f); //loop + + } else { + p.custom[2] = CLAMP(p.custom[2], 0.0f, 1.0); //0 to 1 only + } + } + //apply color + //apply hue rotation + + float tex_scale = 1.0; + if (curve_parameters[PARAM_SCALE].is_valid()) { + tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]); + } + + float tex_hue_variation = 0.0; + if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { + tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]); + } + + float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); + float hue_rot_c = Math::cos(hue_rot_angle); + float hue_rot_s = Math::sin(hue_rot_angle); + + Basis hue_rot_mat; + { + Basis mat1(0.299, 0.587, 0.114, 0.299, 0.587, 0.114, 0.299, 0.587, 0.114); + Basis mat2(0.701, -0.587, -0.114, -0.299, 0.413, -0.114, -0.300, -0.588, 0.886); + Basis mat3(0.168, 0.330, -0.497, -0.328, 0.035, 0.292, 1.250, -1.050, -0.203); + + for (int j = 0; j < 3; j++) { + hue_rot_mat[j] = mat1[j] + mat2[j] * hue_rot_c + mat3[j] * hue_rot_s; + } + } + + if (color_ramp.is_valid()) { + p.color = color_ramp->get_color_at_offset(p.custom[1]) * color; + } else { + p.color = color; + } + + Vector3 color_rgb = hue_rot_mat.xform_inv(Vector3(p.color.r, p.color.g, p.color.b)); + p.color.r = color_rgb.x; + p.color.g = color_rgb.y; + p.color.b = color_rgb.z; + + p.color *= p.base_color; + + if (flags[FLAG_DISABLE_Z]) { + + if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (p.velocity.length() > 0.0) { + p.transform.basis.set_axis(1, p.velocity.normalized()); + } else { + p.transform.basis.set_axis(1, p.transform.basis.get_axis(1)); + } + p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized()); + p.transform.basis.set_axis(2, Vector3(0, 0, 1)); + + } else { + p.transform.basis.set_axis(0, Vector3(Math::cos(p.custom[0]), -Math::sin(p.custom[0]), 0.0)); + p.transform.basis.set_axis(1, Vector3(Math::sin(p.custom[0]), Math::cos(p.custom[0]), 0.0)); + p.transform.basis.set_axis(2, Vector3(0, 0, 1)); + } + + } else { + //orient particle Y towards velocity + if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { + if (p.velocity.length() > 0.0) { + p.transform.basis.set_axis(1, p.velocity.normalized()); + } else { + p.transform.basis.set_axis(1, p.transform.basis.get_axis(1).normalized()); + } + if (p.transform.basis.get_axis(1) == p.transform.basis.get_axis(0)) { + p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized()); + p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized()); + } else { + p.transform.basis.set_axis(2, p.transform.basis.get_axis(0).cross(p.transform.basis.get_axis(1)).normalized()); + p.transform.basis.set_axis(0, p.transform.basis.get_axis(1).cross(p.transform.basis.get_axis(2)).normalized()); + } + } else { + p.transform.basis.orthonormalize(); + } + + //turn particle by rotation in Y + if (flags[FLAG_ROTATE_Y]) { + Basis rot_y(Vector3(0, 1, 0), p.custom[0]); + p.transform.basis = p.transform.basis * rot_y; + } + } + + //scale by scale + float base_scale = Math::lerp(parameters[PARAM_SCALE] * tex_scale, 1.0f, p.scale_rand * randomness[PARAM_SCALE]); + if (base_scale == 0.0) base_scale = 0.000001; + + p.transform.basis.scale(Vector3(1, 1, 1) * base_scale); + + if (flags[FLAG_DISABLE_Z]) { + p.velocity.z = 0.0; + p.transform.origin.z = 0.0; + } + + p.transform.origin += p.velocity * local_delta; + } +} + +void CPUParticles::_update_particle_data_buffer() { +#ifndef NO_THREADS + update_mutex->lock(); +#endif + + { + + int pc = particles.size(); + + PoolVector<int>::Write ow; + int *order = NULL; + + PoolVector<float>::Write w = particle_data.write(); + PoolVector<Particle>::Read r = particles.read(); + float *ptr = w.ptr(); + + Transform un_transform; + if (!local_coords) { + un_transform = get_global_transform().affine_inverse(); + } + + if (draw_order != DRAW_ORDER_INDEX) { + ow = particle_order.write(); + order = ow.ptr(); + + for (int i = 0; i < pc; i++) { + order[i] = i; + } + if (draw_order == DRAW_ORDER_LIFETIME) { + SortArray<int, SortLifetime> sorter; + sorter.compare.particles = r.ptr(); + sorter.sort(order, pc); + } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) { + Camera *c = get_viewport()->get_camera(); + if (c) { + Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close + + if (local_coords) { + dir = un_transform.basis.xform(dir).normalized(); + } + + SortArray<int, SortAxis> sorter; + sorter.compare.particles = r.ptr(); + sorter.compare.axis = dir; + sorter.sort(order, pc); + } + } + } + + for (int i = 0; i < pc; i++) { + + int idx = order ? order[i] : i; + + Transform t = r[idx].transform; + + if (!local_coords) { + t = un_transform * t; + } + + if (r[idx].active) { + ptr[0] = t.basis.elements[0][0]; + ptr[1] = t.basis.elements[0][1]; + ptr[2] = t.basis.elements[0][2]; + ptr[3] = t.origin.x; + ptr[4] = t.basis.elements[1][0]; + ptr[5] = t.basis.elements[1][1]; + ptr[6] = t.basis.elements[1][2]; + ptr[7] = t.origin.y; + ptr[8] = t.basis.elements[2][0]; + ptr[9] = t.basis.elements[2][1]; + ptr[10] = t.basis.elements[2][2]; + ptr[11] = t.origin.z; + } else { + zeromem(ptr, sizeof(float) * 12); + } + + Color c = r[idx].color; + uint8_t *data8 = (uint8_t *)&ptr[12]; + data8[0] = CLAMP(c.r * 255.0, 0, 255); + data8[1] = CLAMP(c.g * 255.0, 0, 255); + data8[2] = CLAMP(c.b * 255.0, 0, 255); + data8[3] = CLAMP(c.a * 255.0, 0, 255); + + ptr[13] = r[idx].custom[0]; + ptr[14] = r[idx].custom[1]; + ptr[15] = r[idx].custom[2]; + ptr[16] = r[idx].custom[3]; + + ptr += 17; + } + } + +#ifndef NO_THREADS + update_mutex->unlock(); +#endif +} + +void CPUParticles::_update_render_thread() { + +#ifndef NO_THREADS + update_mutex->lock(); +#endif + + VS::get_singleton()->multimesh_set_as_bulk_array(multimesh, particle_data); + +#ifndef NO_THREADS + update_mutex->unlock(); +#endif +} + +void CPUParticles::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + if (is_processing_internal()) { + +#ifndef NO_THREADS + update_mutex->lock(); +#endif + VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); +#ifndef NO_THREADS + update_mutex->unlock(); +#endif + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + if (is_processing_internal()) { + +#ifndef NO_THREADS + update_mutex->lock(); +#endif + VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); +#ifndef NO_THREADS + update_mutex->unlock(); +#endif + } + } + + if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { + } + + if (p_what == NOTIFICATION_INTERNAL_PROCESS) { + + if (particles.size() == 0) + return; + + float delta = get_process_delta_time(); + if (emitting) { + + inactive_time = 0; + } else { + inactive_time += delta; + if (inactive_time > lifetime * 1.2) { + set_process_internal(false); +#ifndef NO_THREADS + update_mutex->lock(); +#endif + VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); + +#ifndef NO_THREADS + update_mutex->unlock(); +#endif + //reset variables + time = 0; + inactive_time = 0; + frame_remainder = 0; + cycle = 0; + return; + } + } + + if (time == 0 && pre_process_time > 0.0) { + + float frame_time; + if (fixed_fps > 0) + frame_time = 1.0 / fixed_fps; + else + frame_time = 1.0 / 30.0; + + float todo = pre_process_time; + + while (todo >= 0) { + _particles_process(frame_time); + todo -= frame_time; + } + } + + if (fixed_fps > 0) { + float frame_time = 1.0 / fixed_fps; + float decr = frame_time; + + float ldelta = delta; + if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10 + ldelta = 0.1; + } else if (ldelta <= 0.0) { //unlikely but.. + ldelta = 0.001; + } + float todo = frame_remainder + ldelta; + + while (todo >= frame_time) { + _particles_process(frame_time); + todo -= decr; + } + + frame_remainder = todo; + + } else { + _particles_process(delta); + } + + _update_particle_data_buffer(); + } +} + +void CPUParticles::convert_from_particles(Node *p_particles) { + + Particles *particles = Object::cast_to<Particles>(p_particles); + ERR_FAIL_COND(!particles); + + set_emitting(particles->is_emitting()); + set_amount(particles->get_amount()); + set_lifetime(particles->get_lifetime()); + set_one_shot(particles->get_one_shot()); + set_pre_process_time(particles->get_pre_process_time()); + set_explosiveness_ratio(particles->get_explosiveness_ratio()); + set_randomness_ratio(particles->get_randomness_ratio()); + set_use_local_coordinates(particles->get_use_local_coordinates()); + set_fixed_fps(particles->get_fixed_fps()); + set_fractional_delta(particles->get_fractional_delta()); + set_speed_scale(particles->get_speed_scale()); + set_draw_order(DrawOrder(particles->get_draw_order())); + set_mesh(particles->get_draw_pass_mesh(0)); + + Ref<ParticlesMaterial> material = particles->get_process_material(); + if (material.is_null()) + return; + + set_spread(material->get_spread()); + set_flatness(material->get_flatness()); + + set_color(material->get_color()); + + Ref<GradientTexture> gt = material->get_color_ramp(); + if (gt.is_valid()) { + set_color_ramp(gt->get_gradient()); + } + + set_particle_flag(FLAG_ALIGN_Y_TO_VELOCITY, material->get_flag(ParticlesMaterial::FLAG_ALIGN_Y_TO_VELOCITY)); + set_particle_flag(FLAG_ROTATE_Y, material->get_flag(ParticlesMaterial::FLAG_ROTATE_Y)); + set_particle_flag(FLAG_DISABLE_Z, material->get_flag(ParticlesMaterial::FLAG_DISABLE_Z)); + set_particle_flag(FLAG_ANIM_LOOP, material->get_flag(ParticlesMaterial::FLAG_ANIM_LOOP)); + + set_emission_shape(EmissionShape(material->get_emission_shape())); + set_emission_sphere_radius(material->get_emission_sphere_radius()); + set_emission_box_extents(material->get_emission_box_extents()); + + set_gravity(material->get_gravity()); + +#define CONVERT_PARAM(m_param) \ + set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \ + { \ + Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \ + if (ctex.is_valid()) set_param_curve(m_param, ctex->get_curve()); \ + } \ + set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param)); + + CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY); + CONVERT_PARAM(PARAM_ANGULAR_VELOCITY); + // CONVERT_PARAM(PARAM_ORBIT_VELOCITY); + CONVERT_PARAM(PARAM_LINEAR_ACCEL); + CONVERT_PARAM(PARAM_RADIAL_ACCEL); + CONVERT_PARAM(PARAM_TANGENTIAL_ACCEL); + CONVERT_PARAM(PARAM_DAMPING); + CONVERT_PARAM(PARAM_ANGLE); + CONVERT_PARAM(PARAM_SCALE); + CONVERT_PARAM(PARAM_HUE_VARIATION); + CONVERT_PARAM(PARAM_ANIM_SPEED); + CONVERT_PARAM(PARAM_ANIM_OFFSET); + +#undef CONVERT_PARAM +} + +void CPUParticles::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &CPUParticles::set_emitting); + ClassDB::bind_method(D_METHOD("set_amount", "amount"), &CPUParticles::set_amount); + ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &CPUParticles::set_lifetime); + ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &CPUParticles::set_one_shot); + ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &CPUParticles::set_pre_process_time); + ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &CPUParticles::set_explosiveness_ratio); + ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &CPUParticles::set_randomness_ratio); + ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &CPUParticles::set_use_local_coordinates); + ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &CPUParticles::set_fixed_fps); + ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &CPUParticles::set_fractional_delta); + ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &CPUParticles::set_speed_scale); + + ClassDB::bind_method(D_METHOD("is_emitting"), &CPUParticles::is_emitting); + ClassDB::bind_method(D_METHOD("get_amount"), &CPUParticles::get_amount); + ClassDB::bind_method(D_METHOD("get_lifetime"), &CPUParticles::get_lifetime); + ClassDB::bind_method(D_METHOD("get_one_shot"), &CPUParticles::get_one_shot); + ClassDB::bind_method(D_METHOD("get_pre_process_time"), &CPUParticles::get_pre_process_time); + ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &CPUParticles::get_explosiveness_ratio); + ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &CPUParticles::get_randomness_ratio); + ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &CPUParticles::get_use_local_coordinates); + ClassDB::bind_method(D_METHOD("get_fixed_fps"), &CPUParticles::get_fixed_fps); + ClassDB::bind_method(D_METHOD("get_fractional_delta"), &CPUParticles::get_fractional_delta); + ClassDB::bind_method(D_METHOD("get_speed_scale"), &CPUParticles::get_speed_scale); + + ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &CPUParticles::set_draw_order); + + ClassDB::bind_method(D_METHOD("get_draw_order"), &CPUParticles::get_draw_order); + + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &CPUParticles::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &CPUParticles::get_mesh); + + ClassDB::bind_method(D_METHOD("restart"), &CPUParticles::restart); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); + ADD_GROUP("Time", ""); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); + ADD_GROUP("Drawing", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); + + BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX); + BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); + BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH); + + //////////////////////////////// + + ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles::set_spread); + ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles::get_spread); + + ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles::set_flatness); + ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles::get_flatness); + + ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles::set_param); + ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles::get_param); + + ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles::set_param_randomness); + ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles::get_param_randomness); + + ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles::set_param_curve); + ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles::get_param_curve); + + ClassDB::bind_method(D_METHOD("set_color", "color"), &CPUParticles::set_color); + ClassDB::bind_method(D_METHOD("get_color"), &CPUParticles::get_color); + + ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles::set_color_ramp); + ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles::get_color_ramp); + + ClassDB::bind_method(D_METHOD("set_particle_flag", "flag", "enable"), &CPUParticles::set_particle_flag); + ClassDB::bind_method(D_METHOD("get_particle_flag", "flag"), &CPUParticles::get_particle_flag); + + ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &CPUParticles::set_emission_shape); + ClassDB::bind_method(D_METHOD("get_emission_shape"), &CPUParticles::get_emission_shape); + + ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &CPUParticles::set_emission_sphere_radius); + ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &CPUParticles::get_emission_sphere_radius); + + ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &CPUParticles::set_emission_box_extents); + ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &CPUParticles::get_emission_box_extents); + + ClassDB::bind_method(D_METHOD("set_emission_points", "array"), &CPUParticles::set_emission_points); + ClassDB::bind_method(D_METHOD("get_emission_points"), &CPUParticles::get_emission_points); + + ClassDB::bind_method(D_METHOD("set_emission_normals", "array"), &CPUParticles::set_emission_normals); + ClassDB::bind_method(D_METHOD("get_emission_normals"), &CPUParticles::get_emission_normals); + + ClassDB::bind_method(D_METHOD("set_emission_colors", "array"), &CPUParticles::set_emission_colors); + ClassDB::bind_method(D_METHOD("get_emission_colors"), &CPUParticles::get_emission_colors); + + ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles::get_gravity); + ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles::set_gravity); + + ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles::convert_from_particles); + + ClassDB::bind_method(D_METHOD("_update_render_thread"), &CPUParticles::_update_render_thread); + + ADD_GROUP("Emission Shape", "emission_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "set_emission_sphere_radius", "get_emission_sphere_radius"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); + ADD_GROUP("Flags", "flag_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_particle_flag", "get_particle_flag", FLAG_ALIGN_Y_TO_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_particle_flag", "get_particle_flag", FLAG_ROTATE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_particle_flag", "get_particle_flag", FLAG_DISABLE_Z); + ADD_GROUP("Spread", ""); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); + ADD_GROUP("Gravity", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); + ADD_GROUP("Initial Velocity", "initial_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_GROUP("Angular Velocity", "angular_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); + /* + ADD_GROUP("Orbit Velocity", "orbit_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); +*/ + ADD_GROUP("Linear Accel", "linear_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL); + ADD_GROUP("Radial Accel", "radial_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL); + ADD_GROUP("Tangential Accel", "tangential_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); + ADD_GROUP("Damping", ""); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); + ADD_GROUP("Angle", ""); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); + ADD_GROUP("Scale", ""); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE); + ADD_GROUP("Color", ""); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp"); + + ADD_GROUP("Hue Variation", "hue_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION); + ADD_GROUP("Animation", "anim_"); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_particle_flag", "get_particle_flag", FLAG_ANIM_LOOP); + + BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); + //BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); + BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); + BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); + BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); + BIND_ENUM_CONSTANT(PARAM_DAMPING); + BIND_ENUM_CONSTANT(PARAM_ANGLE); + BIND_ENUM_CONSTANT(PARAM_SCALE); + BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION); + BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED); + BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); + BIND_ENUM_CONSTANT(PARAM_MAX); + + BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); + BIND_ENUM_CONSTANT(FLAG_MAX); + + BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); +} + +CPUParticles::CPUParticles() { + + time = 0; + inactive_time = 0; + frame_remainder = 0; + cycle = 0; + + multimesh = VisualServer::get_singleton()->multimesh_create(); + set_base(multimesh); + + set_emitting(true); + set_one_shot(false); + set_amount(8); + set_lifetime(1); + set_fixed_fps(0); + set_fractional_delta(true); + set_pre_process_time(0); + set_explosiveness_ratio(0); + set_randomness_ratio(0); + set_use_local_coordinates(true); + + set_draw_order(DRAW_ORDER_INDEX); + set_speed_scale(1); + + set_spread(45); + set_flatness(0); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); + //set_param(PARAM_ORBIT_VELOCITY, 0); + set_param(PARAM_LINEAR_ACCEL, 0); + set_param(PARAM_RADIAL_ACCEL, 0); + set_param(PARAM_TANGENTIAL_ACCEL, 0); + set_param(PARAM_DAMPING, 0); + set_param(PARAM_ANGLE, 0); + set_param(PARAM_SCALE, 1); + set_param(PARAM_HUE_VARIATION, 0); + set_param(PARAM_ANIM_SPEED, 0); + set_param(PARAM_ANIM_OFFSET, 0); + set_emission_shape(EMISSION_SHAPE_POINT); + set_emission_sphere_radius(1); + set_emission_box_extents(Vector3(1, 1, 1)); + + set_gravity(Vector3(0, -9.8, 0)); + + for (int i = 0; i < PARAM_MAX; i++) { + set_param_randomness(Parameter(i), 0); + } + + for (int i = 0; i < FLAG_MAX; i++) { + flags[i] = false; + } + + set_color(Color(1, 1, 1, 1)); + +#ifndef NO_THREADS + update_mutex = Mutex::create(); +#endif +} + +CPUParticles::~CPUParticles() { + VS::get_singleton()->free(multimesh); + +#ifndef NO_THREADS + memdelete(update_mutex); +#endif +} diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h new file mode 100644 index 0000000000..47d0ef3f5e --- /dev/null +++ b/scene/3d/cpu_particles.h @@ -0,0 +1,287 @@ +/*************************************************************************/ +/* cpu_particles.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CPU_PARTICLES_H +#define CPU_PARTICLES_H + +#include "rid.h" +#include "scene/3d/visual_instance.h" + +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + +class CPUParticles : public GeometryInstance { +private: + GDCLASS(CPUParticles, GeometryInstance); + +public: + enum DrawOrder { + DRAW_ORDER_INDEX, + DRAW_ORDER_LIFETIME, + DRAW_ORDER_VIEW_DEPTH, + }; + + enum Parameter { + + PARAM_INITIAL_LINEAR_VELOCITY, + PARAM_ANGULAR_VELOCITY, + //PARAM_ORBIT_VELOCITY, + PARAM_LINEAR_ACCEL, + PARAM_RADIAL_ACCEL, + PARAM_TANGENTIAL_ACCEL, + PARAM_DAMPING, + PARAM_ANGLE, + PARAM_SCALE, + PARAM_HUE_VARIATION, + PARAM_ANIM_SPEED, + PARAM_ANIM_OFFSET, + PARAM_MAX + }; + + enum Flags { + FLAG_ALIGN_Y_TO_VELOCITY, + FLAG_ROTATE_Y, + FLAG_DISABLE_Z, + FLAG_ANIM_LOOP, + FLAG_MAX + }; + + enum EmissionShape { + EMISSION_SHAPE_POINT, + EMISSION_SHAPE_SPHERE, + EMISSION_SHAPE_BOX, + EMISSION_SHAPE_POINTS, + EMISSION_SHAPE_DIRECTED_POINTS, + }; + +private: + bool emitting; + + struct Particle { + Transform transform; + Color color; + float custom[4]; + Vector3 velocity; + bool active; + float angle_rand; + float scale_rand; + float hue_rot_rand; + float anim_offset_rand; + float time; + Color base_color; + + uint32_t seed; + }; + + float time; + float inactive_time; + float frame_remainder; + int cycle; + + RID multimesh; + + PoolVector<Particle> particles; + PoolVector<float> particle_data; + PoolVector<int> particle_order; + + struct SortLifetime { + const Particle *particles; + + bool operator()(int p_a, int p_b) const { + return particles[p_a].time < particles[p_b].time; + } + }; + + struct SortAxis { + const Particle *particles; + Vector3 axis; + bool operator()(int p_a, int p_b) const { + + return axis.dot(particles[p_a].transform.origin) < axis.dot(particles[p_b].transform.origin); + } + }; + + // + + bool one_shot; + + float lifetime; + float pre_process_time; + float explosiveness_ratio; + float randomness_ratio; + float speed_scale; + bool local_coords; + int fixed_fps; + bool fractional_delta; + + DrawOrder draw_order; + + Ref<Mesh> mesh; + + //////// + + float spread; + float flatness; + + float parameters[PARAM_MAX]; + float randomness[PARAM_MAX]; + + Ref<Curve> curve_parameters[PARAM_MAX]; + Color color; + Ref<Gradient> color_ramp; + + bool flags[FLAG_MAX]; + + EmissionShape emission_shape; + float emission_sphere_radius; + Vector3 emission_box_extents; + PoolVector<Vector3> emission_points; + PoolVector<Vector3> emission_normals; + PoolVector<Color> emission_colors; + int emission_point_count; + + bool anim_loop; + Vector3 gravity; + + void _particles_process(float p_delta); + void _update_particle_data_buffer(); + + Mutex *update_mutex; + + void _update_render_thread(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + virtual void _validate_property(PropertyInfo &property) const; + +public: + AABB get_aabb() const; + PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void set_emitting(bool p_emitting); + void set_amount(int p_amount); + void set_lifetime(float p_lifetime); + void set_one_shot(bool p_one_shot); + void set_pre_process_time(float p_time); + void set_explosiveness_ratio(float p_ratio); + void set_randomness_ratio(float p_ratio); + void set_visibility_aabb(const AABB &p_aabb); + void set_use_local_coordinates(bool p_enable); + void set_speed_scale(float p_scale); + + bool is_emitting() const; + int get_amount() const; + float get_lifetime() const; + bool get_one_shot() const; + float get_pre_process_time() const; + float get_explosiveness_ratio() const; + float get_randomness_ratio() const; + AABB get_visibility_aabb() const; + bool get_use_local_coordinates() const; + float get_speed_scale() const; + + void set_fixed_fps(int p_count); + int get_fixed_fps() const; + + void set_fractional_delta(bool p_enable); + bool get_fractional_delta() const; + + void set_draw_order(DrawOrder p_order); + DrawOrder get_draw_order() const; + + void set_draw_passes(int p_count); + int get_draw_passes() const; + + void set_mesh(const Ref<Mesh> &p_mesh); + Ref<Mesh> get_mesh() const; + + /////////////////// + + void set_spread(float p_spread); + float get_spread() const; + + void set_flatness(float p_flatness); + float get_flatness() const; + + void set_param(Parameter p_param, float p_value); + float get_param(Parameter p_param) const; + + void set_param_randomness(Parameter p_param, float p_value); + float get_param_randomness(Parameter p_param) const; + + void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve); + Ref<Curve> get_param_curve(Parameter p_param) const; + + void set_color(const Color &p_color); + Color get_color() const; + + void set_color_ramp(const Ref<Gradient> &p_texture); + Ref<Gradient> get_color_ramp() const; + + void set_particle_flag(Flags p_flag, bool p_enable); + bool get_particle_flag(Flags p_flag) const; + + void set_emission_shape(EmissionShape p_shape); + void set_emission_sphere_radius(float p_radius); + void set_emission_box_extents(Vector3 p_extents); + void set_emission_points(const PoolVector<Vector3> &p_points); + void set_emission_normals(const PoolVector<Vector3> &p_normals); + void set_emission_colors(const PoolVector<Color> &p_colors); + void set_emission_point_count(int p_count); + + EmissionShape get_emission_shape() const; + float get_emission_sphere_radius() const; + Vector3 get_emission_box_extents() const; + PoolVector<Vector3> get_emission_points() const; + PoolVector<Vector3> get_emission_normals() const; + PoolVector<Color> get_emission_colors() const; + int get_emission_point_count() const; + + void set_gravity(const Vector3 &p_gravity); + Vector3 get_gravity() const; + + virtual String get_configuration_warning() const; + + void restart(); + + void convert_from_particles(Node *p_particles); + + CPUParticles(); + ~CPUParticles(); +}; + +VARIANT_ENUM_CAST(CPUParticles::DrawOrder) +VARIANT_ENUM_CAST(CPUParticles::Parameter) +VARIANT_ENUM_CAST(CPUParticles::Flags) +VARIANT_ENUM_CAST(CPUParticles::EmissionShape) + +#endif // CPU_PARTICLES_H diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 4ad2eb60ee..6276d02eff 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -557,6 +557,7 @@ GIProbe::GIProbe() { compress = false; gi_probe = VS::get_singleton()->gi_probe_create(); + set_disable_scale(true); } GIProbe::~GIProbe() { diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 7c42638107..16164cf3bf 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -306,6 +306,7 @@ Light::Light(VisualServer::LightType p_type) { set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5); set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0); set_param(PARAM_SHADOW_BIAS, 0.15); + set_disable_scale(true); } Light::Light() { diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 80bae911d4..e277cae5b7 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -36,6 +36,7 @@ #include "scene/resources/material.h" #include "scene/scene_string_names.h" #include "skeleton.h" + bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) { //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else. @@ -256,7 +257,7 @@ void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_ma ERR_FAIL_INDEX(p_surface, materials.size()); - materials[p_surface] = p_material; + materials.write[p_surface] = p_material; if (materials[p_surface].is_valid()) VS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid()); @@ -371,7 +372,7 @@ void MeshInstance::_bind_methods() { ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); } MeshInstance::MeshInstance() { diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index 5d359cd4d5..0dfec538f9 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -41,6 +41,7 @@ class MeshInstance : public GeometryInstance { GDCLASS(MeshInstance, GeometryInstance); +protected: Ref<Mesh> mesh; NodePath skeleton_path; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 77bf703706..8d84d2408c 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -73,7 +73,7 @@ void Navigation::_navmesh_link(int p_id) { Vector3 ep = nm.xform.xform(r[idx]); center += ep; e.point = _get_point(ep); - p.edges[j] = e; + p.edges.write[j] = e; if (j >= 2) { Vector3 epa = nm.xform.xform(r[indices[j - 2]]); @@ -118,18 +118,16 @@ void Navigation::_navmesh_link(int p_id) { ConnectionPending pending; pending.polygon = &p; pending.edge = j; - p.edges[j].P = C->get().pending.push_back(pending); + p.edges.write[j].P = C->get().pending.push_back(pending); continue; - //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); } - //ERR_CONTINUE(C->get().B!=NULL); //wut C->get().B = &p; C->get().B_edge = j; - C->get().A->edges[C->get().A_edge].C = &p; - C->get().A->edges[C->get().A_edge].C_edge = j; - p.edges[j].C = C->get().A; - p.edges[j].C_edge = C->get().A_edge; + C->get().A->edges.write[C->get().A_edge].C = &p; + C->get().A->edges.write[C->get().A_edge].C_edge = j; + p.edges.write[j].C = C->get().A; + p.edges.write[j].C_edge = C->get().A_edge; //connection successful. } } @@ -165,10 +163,10 @@ void Navigation::_navmesh_unlink(int p_id) { } else if (C->get().B) { //disconnect - C->get().B->edges[C->get().B_edge].C = NULL; - C->get().B->edges[C->get().B_edge].C_edge = -1; - C->get().A->edges[C->get().A_edge].C = NULL; - C->get().A->edges[C->get().A_edge].C_edge = -1; + C->get().B->edges.write[C->get().B_edge].C = NULL; + C->get().B->edges.write[C->get().B_edge].C_edge = -1; + C->get().A->edges.write[C->get().A_edge].C = NULL; + C->get().A->edges.write[C->get().A_edge].C_edge = -1; if (C->get().A == &E->get()) { @@ -185,11 +183,11 @@ void Navigation::_navmesh_unlink(int p_id) { C->get().B = cp.polygon; C->get().B_edge = cp.edge; - C->get().A->edges[C->get().A_edge].C = cp.polygon; - C->get().A->edges[C->get().A_edge].C_edge = cp.edge; - cp.polygon->edges[cp.edge].C = C->get().A; - cp.polygon->edges[cp.edge].C_edge = C->get().A_edge; - cp.polygon->edges[cp.edge].P = NULL; + C->get().A->edges.write[C->get().A_edge].C = cp.polygon; + C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; + cp.polygon->edges.write[cp.edge].C = C->get().A; + cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; + cp.polygon->edges.write[cp.edge].P = NULL; } } else { @@ -312,7 +310,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector if (!begin_poly || !end_poly) { - //print_line("No Path Path"); return Vector<Vector3>(); //no path } @@ -320,9 +317,8 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector Vector<Vector3> path; path.resize(2); - path[0] = begin_point; - path[1] = end_point; - //print_line("Direct Path"); + path.write[0] = begin_point; + path.write[1] = end_point; return path; } @@ -347,7 +343,6 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector while (!found_route) { if (open_list.size() == 0) { - //print_line("NOU OPEN LIST"); break; } //check open list @@ -375,7 +370,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector for (int i = 0; i < p->edges.size(); i++) { - Polygon::Edge &e = p->edges[i]; + Polygon::Edge &e = p->edges.write[i]; if (!e.C) continue; @@ -581,10 +576,6 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3 &p_from, const Ve } } - if (closest_navmesh && closest_navmesh->owner) { - //print_line("navmesh is: "+Object::cast_to<Node>(closest_navmesh->owner)->get_name()); - } - return closest_point; } diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 073e56fdb4..99680b7273 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -55,9 +55,9 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { for (int j = 0; j < rlen; j += 3) { Vector<int> vi; vi.resize(3); - vi[0] = r[j + 0] + from; - vi[1] = r[j + 1] + from; - vi[2] = r[j + 2] + from; + vi.write[0] = r[j + 0] + from; + vi.write[1] = r[j + 1] + from; + vi.write[2] = r[j + 2] + from; add_polygon(vi); } @@ -215,7 +215,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) { polygons.resize(p_array.size()); for (int i = 0; i < p_array.size(); i++) { - polygons[i].indices = p_array[i]; + polygons.write[i].indices = p_array[i]; } } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 2b3a62fcdc..10b26778ef 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "particles.h" -#include "scene/resources/surface_tool.h" + #include "servers/visual_server.h" AABB Particles::get_aabb() const { @@ -185,7 +185,7 @@ void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) { ERR_FAIL_INDEX(p_pass, draw_passes.size()); - draw_passes[p_pass] = p_mesh; + draw_passes.write[p_pass] = p_mesh; RID mesh_rid; if (p_mesh.is_valid()) @@ -329,7 +329,7 @@ void Particles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); @@ -378,1219 +378,3 @@ Particles::~Particles() { VS::get_singleton()->free(particles); } - -////////////////////////////////////// - -Mutex *ParticlesMaterial::material_mutex = NULL; -SelfList<ParticlesMaterial>::List ParticlesMaterial::dirty_materials; -Map<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData> ParticlesMaterial::shader_map; -ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = NULL; - -void ParticlesMaterial::init_shaders() { - -#ifndef NO_THREADS - material_mutex = Mutex::create(); -#endif - - shader_names = memnew(ShaderNames); - - shader_names->spread = "spread"; - shader_names->flatness = "flatness"; - shader_names->initial_linear_velocity = "initial_linear_velocity"; - shader_names->initial_angle = "initial_angle"; - shader_names->angular_velocity = "angular_velocity"; - shader_names->orbit_velocity = "orbit_velocity"; - shader_names->linear_accel = "linear_accel"; - shader_names->radial_accel = "radial_accel"; - shader_names->tangent_accel = "tangent_accel"; - shader_names->damping = "damping"; - shader_names->scale = "scale"; - shader_names->hue_variation = "hue_variation"; - shader_names->anim_speed = "anim_speed"; - shader_names->anim_offset = "anim_offset"; - - shader_names->initial_linear_velocity_random = "initial_linear_velocity_random"; - shader_names->initial_angle_random = "initial_angle_random"; - shader_names->angular_velocity_random = "angular_velocity_random"; - shader_names->orbit_velocity_random = "orbit_velocity_random"; - shader_names->linear_accel_random = "linear_accel_random"; - shader_names->radial_accel_random = "radial_accel_random"; - shader_names->tangent_accel_random = "tangent_accel_random"; - shader_names->damping_random = "damping_random"; - shader_names->scale_random = "scale_random"; - shader_names->hue_variation_random = "hue_variation_random"; - shader_names->anim_speed_random = "anim_speed_random"; - shader_names->anim_offset_random = "anim_offset_random"; - - shader_names->angle_texture = "angle_texture"; - shader_names->angular_velocity_texture = "angular_velocity_texture"; - shader_names->orbit_velocity_texture = "orbit_velocity_texture"; - shader_names->linear_accel_texture = "linear_accel_texture"; - shader_names->radial_accel_texture = "radial_accel_texture"; - shader_names->tangent_accel_texture = "tangent_accel_texture"; - shader_names->damping_texture = "damping_texture"; - shader_names->scale_texture = "scale_texture"; - shader_names->hue_variation_texture = "hue_variation_texture"; - shader_names->anim_speed_texture = "anim_speed_texture"; - shader_names->anim_offset_texture = "anim_offset_texture"; - - shader_names->color = "color_value"; - shader_names->color_ramp = "color_ramp"; - - shader_names->emission_sphere_radius = "emission_sphere_radius"; - shader_names->emission_box_extents = "emission_box_extents"; - shader_names->emission_texture_point_count = "emission_texture_point_count"; - shader_names->emission_texture_points = "emission_texture_points"; - shader_names->emission_texture_normal = "emission_texture_normal"; - shader_names->emission_texture_color = "emission_texture_color"; - - shader_names->trail_divisor = "trail_divisor"; - shader_names->trail_size_modifier = "trail_size_modifier"; - shader_names->trail_color_modifier = "trail_color_modifier"; - - shader_names->gravity = "gravity"; -} - -void ParticlesMaterial::finish_shaders() { - -#ifndef NO_THREADS - memdelete(material_mutex); -#endif - - memdelete(shader_names); -} - -void ParticlesMaterial::_update_shader() { - - dirty_materials.remove(&element); - - MaterialKey mk = _compute_key(); - if (mk.key == current_key.key) - return; //no update required in the end - - 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); - } - } - - current_key = mk; - - if (shader_map.has(mk)) { - - VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); - shader_map[mk].users++; - return; - } - - //must create a shader! - - String code = "shader_type particles;\n"; - - code += "uniform float spread;\n"; - code += "uniform float flatness;\n"; - code += "uniform float initial_linear_velocity;\n"; - code += "uniform float initial_angle;\n"; - code += "uniform float angular_velocity;\n"; - code += "uniform float orbit_velocity;\n"; - code += "uniform float linear_accel;\n"; - code += "uniform float radial_accel;\n"; - code += "uniform float tangent_accel;\n"; - code += "uniform float damping;\n"; - code += "uniform float scale;\n"; - code += "uniform float hue_variation;\n"; - code += "uniform float anim_speed;\n"; - code += "uniform float anim_offset;\n"; - - code += "uniform float initial_linear_velocity_random;\n"; - code += "uniform float initial_angle_random;\n"; - code += "uniform float angular_velocity_random;\n"; - code += "uniform float orbit_velocity_random;\n"; - code += "uniform float linear_accel_random;\n"; - code += "uniform float radial_accel_random;\n"; - code += "uniform float tangent_accel_random;\n"; - code += "uniform float damping_random;\n"; - code += "uniform float scale_random;\n"; - code += "uniform float hue_variation_random;\n"; - code += "uniform float anim_speed_random;\n"; - code += "uniform float anim_offset_random;\n"; - - switch (emission_shape) { - case EMISSION_SHAPE_POINT: { - //do none - } break; - case EMISSION_SHAPE_SPHERE: { - code += "uniform float emission_sphere_radius;\n"; - } break; - case EMISSION_SHAPE_BOX: { - code += "uniform vec3 emission_box_extents;\n"; - } break; - case EMISSION_SHAPE_DIRECTED_POINTS: { - code += "uniform sampler2D emission_texture_normal : hint_black;\n"; - } //fallthrough - case EMISSION_SHAPE_POINTS: { - code += "uniform sampler2D emission_texture_points : hint_black;\n"; - code += "uniform int emission_texture_point_count;\n"; - if (emission_color_texture.is_valid()) { - code += "uniform sampler2D emission_texture_color : hint_white;\n"; - } - } break; - } - - code += "uniform vec4 color_value : hint_color;\n"; - - code += "uniform int trail_divisor;\n"; - - code += "uniform vec3 gravity;\n"; - - if (color_ramp.is_valid()) - code += "uniform sampler2D color_ramp;\n"; - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) - code += "uniform sampler2D linear_velocity_texture;\n"; - if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) - code += "uniform sampler2D orbit_velocity_texture;\n"; - if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) - code += "uniform sampler2D angular_velocity_texture;\n"; - if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) - code += "uniform sampler2D linear_accel_texture;\n"; - if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) - code += "uniform sampler2D radial_accel_texture;\n"; - if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) - code += "uniform sampler2D tangent_accel_texture;\n"; - if (tex_parameters[PARAM_DAMPING].is_valid()) - code += "uniform sampler2D damping_texture;\n"; - if (tex_parameters[PARAM_ANGLE].is_valid()) - code += "uniform sampler2D angle_texture;\n"; - if (tex_parameters[PARAM_SCALE].is_valid()) - code += "uniform sampler2D scale_texture;\n"; - if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) - code += "uniform sampler2D hue_variation_texture;\n"; - if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) - code += "uniform sampler2D anim_speed_texture;\n"; - if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) - code += "uniform sampler2D anim_offset_texture;\n"; - - if (trail_size_modifier.is_valid()) { - code += "uniform sampler2D trail_size_modifier;\n"; - } - - if (trail_color_modifier.is_valid()) { - code += "uniform sampler2D trail_color_modifier;\n"; - } - - //need a random function - code += "\n\n"; - code += "float rand_from_seed(inout uint seed) {\n"; - code += " int k;\n"; - code += " int s = int(seed);\n"; - code += " if (s == 0)\n"; - code += " s = 305420679;\n"; - code += " k = s / 127773;\n"; - code += " s = 16807 * (s - k * 127773) - 2836 * k;\n"; - code += " if (s < 0)\n"; - code += " s += 2147483647;\n"; - code += " seed = uint(s);\n"; - code += " return float(seed % uint(65536))/65535.0;\n"; - code += "}\n"; - code += "\n"; - - code += "float rand_from_seed_m1_p1(inout uint seed) {\n"; - code += " return rand_from_seed(seed)*2.0-1.0;\n"; - code += "}\n"; - code += "\n"; - - //improve seed quality - code += "uint hash(uint x) {\n"; - code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; - code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; - code += " x = (x >> uint(16)) ^ x;\n"; - code += " return x;\n"; - code += "}\n"; - code += "\n"; - - code += "void vertex() {\n"; - code += " uint base_number = NUMBER/uint(trail_divisor);\n"; - code += " uint alt_seed = hash(base_number+uint(1)+RANDOM_SEED);\n"; - code += " float angle_rand = rand_from_seed(alt_seed);\n"; - code += " float scale_rand = rand_from_seed(alt_seed);\n"; - code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; - code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; - code += " float pi = 3.14159;\n"; - code += " float degree_to_rad = pi / 180.0;\n"; - code += "\n"; - - if (emission_shape >= EMISSION_SHAPE_POINTS) { - code += " int point = min(emission_texture_point_count-1,int(rand_from_seed(alt_seed) * float(emission_texture_point_count)));\n"; - code += " ivec2 emission_tex_size = textureSize( emission_texture_points, 0 );\n"; - code += " ivec2 emission_tex_ofs = ivec2( point % emission_tex_size.x, point / emission_tex_size.x );\n"; - } - code += " if (RESTART) {\n"; - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) - code += " float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(0.0,0.0),0.0).r;\n"; - else - code += " float tex_linear_velocity = 0.0;\n"; - - if (tex_parameters[PARAM_ANGLE].is_valid()) - code += " float tex_angle = textureLod(angle_texture,vec2(0.0,0.0),0.0).r;\n"; - else - code += " float tex_angle = 0.0;\n"; - - if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) - code += " float tex_anim_offset = textureLod(anim_offset_texture,vec2(0.0,0.0),0.0).r;\n"; - else - code += " float tex_anim_offset = 0.0;\n"; - - code += " float spread_rad = spread*degree_to_rad;\n"; - - if (flags[FLAG_DISABLE_Z]) { - - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n"; - code += " vec3 rot = vec3( cos(angle1_rad), sin(angle1_rad),0.0 );\n"; - code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; - - } else { - //initiate velocity spread in 3D - code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n"; - code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad*(1.0-flatness);\n"; - code += " vec3 direction_xz = vec3( sin(angle1_rad), 0, cos(angle1_rad));\n"; - code += " vec3 direction_yz = vec3( 0, sin(angle2_rad), cos(angle2_rad));\n"; - code += " direction_yz.z = direction_yz.z / sqrt(direction_yz.z); //better uniform distribution\n"; - code += " vec3 direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; - code += " direction = normalize(direction);\n"; - code += " VELOCITY = direction*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; - } - - code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; - code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle - code += " CUSTOM.y = 0.0;\n"; //phase - code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1) - switch (emission_shape) { - case EMISSION_SHAPE_POINT: { - //do none - } break; - case EMISSION_SHAPE_SPHERE: { - code += " TRANSFORM[3].xyz = normalize(vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0 ))*emission_sphere_radius;\n"; - } break; - case EMISSION_SHAPE_BOX: { - code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0-1.0, rand_from_seed(alt_seed) * 2.0-1.0)*emission_box_extents;\n"; - } break; - case EMISSION_SHAPE_POINTS: - case EMISSION_SHAPE_DIRECTED_POINTS: { - code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs,0).xyz;\n"; - - if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) { - if (flags[FLAG_DISABLE_Z]) { - - code += " mat2 rotm;"; - code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs,0).xy;\n"; - code += " rotm[1] = rotm[0].yx * vec2(1.0,-1.0);\n"; - code += " VELOCITY.xy = rotm * VELOCITY.xy;\n"; - } else { - code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs,0).xyz;\n"; - code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0, 1.0, 0.0);\n"; - code += " vec3 tangent = normalize(cross(v0, normal));\n"; - code += " vec3 bitangent = normalize(cross(tangent, normal));\n"; - code += " VELOCITY = mat3(tangent,bitangent,normal) * VELOCITY;\n"; - } - } - } break; - } - code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY,0.0)).xyz;\n"; - code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; - if (flags[FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.0;\n"; - code += " TRANSFORM[3].z = 0.0;\n"; - } - - code += " } else {\n"; - - code += " CUSTOM.y += DELTA/LIFETIME;\n"; - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) - code += " float tex_linear_velocity = textureLod(linear_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_linear_velocity = 0.0;\n"; - - if (flags[FLAG_DISABLE_Z]) { - - if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) - code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_orbit_velocity = 0.0;\n"; - } - - if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) - code += " float tex_angular_velocity = textureLod(angular_velocity_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_angular_velocity = 0.0;\n"; - - if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) - code += " float tex_linear_accel = textureLod(linear_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_linear_accel = 0.0;\n"; - - if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) - code += " float tex_radial_accel = textureLod(radial_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_radial_accel = 0.0;\n"; - - if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) - code += " float tex_tangent_accel = textureLod(tangent_accel_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_tangent_accel = 0.0;\n"; - - if (tex_parameters[PARAM_DAMPING].is_valid()) - code += " float tex_damping = textureLod(damping_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_damping = 0.0;\n"; - - if (tex_parameters[PARAM_ANGLE].is_valid()) - code += " float tex_angle = textureLod(angle_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_angle = 0.0;\n"; - - if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) - code += " float tex_anim_speed = textureLod(anim_speed_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_anim_speed = 0.0;\n"; - - if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) - code += " float tex_anim_offset = textureLod(anim_offset_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_anim_offset = 0.0;\n"; - - code += " vec3 force = gravity; \n"; - code += " vec3 pos = TRANSFORM[3].xyz; \n"; - if (flags[FLAG_DISABLE_Z]) { - code += " pos.z = 0.0; \n"; - } - code += " //apply linear acceleration\n"; - code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel+tex_linear_accel)*mix(1.0,rand_from_seed(alt_seed),linear_accel_random) : vec3(0.0);\n"; - code += " //apply radial acceleration\n"; - code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n"; - code += " vec3 diff = pos-org;\n"; - code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel+tex_radial_accel)*mix(1.0,rand_from_seed(alt_seed),radial_accel_random) : vec3(0.0);\n"; - code += " //apply tangential acceleration;\n"; - if (flags[FLAG_DISABLE_Z]) { - code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0,1.0)),0.0) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),tangent_accel_random)) : vec3(0.0);\n"; - - } else { - code += " vec3 crossDiff = cross(normalize(diff),normalize(gravity));\n"; - code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel+tex_tangent_accel)*mix(1.0,rand_from_seed(alt_seed),tangent_accel_random)) : vec3(0.0);\n"; - } - code += " //apply attractor forces\n"; - code += " VELOCITY += force * DELTA;\n"; - code += " //orbit velocity\n"; - if (flags[FLAG_DISABLE_Z]) { - - code += " float orbit_amount = (orbit_velocity+tex_orbit_velocity)*mix(1.0,rand_from_seed(alt_seed),orbit_velocity_random);\n"; - code += " if (orbit_amount!=0.0) {\n"; - code += " float ang = orbit_amount * DELTA * pi * 2.0;\n"; - code += " mat2 rot = mat2(vec2(cos(ang),-sin(ang)),vec2(sin(ang),cos(ang)));\n"; - code += " TRANSFORM[3].xy-=diff.xy;\n"; - code += " TRANSFORM[3].xy+=rot * diff.xy;\n"; - code += " }\n"; - } - - if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " VELOCITY = normalize(VELOCITY)*tex_linear_velocity;\n"; - } - code += " if (damping + tex_damping > 0.0) {\n"; - code += " \n"; - code += " float v = length(VELOCITY);\n"; - code += " float damp = (damping+tex_damping)*mix(1.0,rand_from_seed(alt_seed),damping_random);\n"; - code += " v -= damp * DELTA;\n"; - code += " if (v < 0.0) {\n"; - code += " VELOCITY = vec3(0.0);\n"; - code += " } else {\n"; - code += " VELOCITY = normalize(VELOCITY) * v;\n"; - code += " }\n"; - code += " }\n"; - code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; - code += " base_angle += CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n"; - code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle - code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle - if (flags[FLAG_ANIM_LOOP]) { - code += " CUSTOM.z = mod(CUSTOM.z,1.0);\n"; //loop - - } else { - code += " CUSTOM.z = clamp(CUSTOM.z,0.0,1.0);\n"; //0 to 1 only - } - code += " }\n"; - //apply color - //apply hue rotation - if (tex_parameters[PARAM_SCALE].is_valid()) - code += " float tex_scale = textureLod(scale_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_scale = 1.0;\n"; - - if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) - code += " float tex_hue_variation = textureLod(hue_variation_texture,vec2(CUSTOM.y,0.0),0.0).r;\n"; - else - code += " float tex_hue_variation = 0.0;\n"; - - code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*pi*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n"; - code += " float hue_rot_c = cos(hue_rot_angle);\n"; - code += " float hue_rot_s = sin(hue_rot_angle);\n"; - code += " mat4 hue_rot_mat = mat4( vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.299, 0.587, 0.114, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 1.0)) +\n"; - code += " mat4( vec4(0.701, -0.587, -0.114, 0.0),\n"; - code += " vec4(-0.299, 0.413, -0.114, 0.0),\n"; - code += " vec4(-0.300, -0.588, 0.886, 0.0),\n"; - code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_c +\n"; - code += " mat4( vec4(0.168, 0.330, -0.497, 0.0),\n"; - code += " vec4(-0.328, 0.035, 0.292, 0.0),\n"; - 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 = hue_rot_mat * textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0);\n"; - } else { - 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"; - } - if (trail_color_modifier.is_valid()) { - code += " if (trail_divisor > 1) { COLOR *= textureLod(trail_color_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0); }\n"; - } - code += "\n"; - - if (flags[FLAG_DISABLE_Z]) { - - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { - code += " if (length(VELOCITY) > 0.0) { TRANSFORM[1].xyz = normalize(VELOCITY); } else { TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz); }\n"; - code += " TRANSFORM[0].xyz = normalize(cross(TRANSFORM[1].xyz,TRANSFORM[2].xyz));\n"; - code += " TRANSFORM[2] = vec4(0.0,0.0,1.0,0.0);\n"; - } else { - code += " TRANSFORM[0] = vec4(cos(CUSTOM.x),-sin(CUSTOM.x),0.0,0.0);\n"; - code += " TRANSFORM[1] = vec4(sin(CUSTOM.x),cos(CUSTOM.x),0.0,0.0);\n"; - code += " TRANSFORM[2] = vec4(0.0,0.0,1.0,0.0);\n"; - } - - } else { - //orient particle Y towards velocity - if (flags[FLAG_ALIGN_Y_TO_VELOCITY]) { - code += " if (length(VELOCITY) > 0.0) { TRANSFORM[1].xyz = normalize(VELOCITY); } else { TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz); }\n"; - code += " if (TRANSFORM[1].xyz == normalize(TRANSFORM[0].xyz)) {\n"; - code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n"; - code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n"; - code += " } else {\n"; - code += " TRANSFORM[2].xyz = normalize(cross(normalize(TRANSFORM[0].xyz),normalize(TRANSFORM[1].xyz)));\n"; - code += " TRANSFORM[0].xyz = normalize(cross(normalize(TRANSFORM[1].xyz),normalize(TRANSFORM[2].xyz)));\n"; - code += " }\n"; - } else { - code += " TRANSFORM[0].xyz = normalize(TRANSFORM[0].xyz);\n"; - code += " TRANSFORM[1].xyz = normalize(TRANSFORM[1].xyz);\n"; - code += " TRANSFORM[2].xyz = normalize(TRANSFORM[2].xyz);\n"; - } - //turn particle by rotation in Y - if (flags[FLAG_ROTATE_Y]) { - code += " TRANSFORM = TRANSFORM * mat4( vec4(cos(CUSTOM.x),0.0,-sin(CUSTOM.x),0.0), vec4(0.0,1.0,0.0,0.0),vec4(sin(CUSTOM.x),0.0,cos(CUSTOM.x),0.0),vec4(0.0,0.0,0.0,1.0));\n"; - } - } - //scale by scale - code += " float base_scale = mix(scale*tex_scale,1.0,scale_random*scale_rand);\n"; - code += " if (base_scale==0.0) base_scale=0.000001;\n"; - if (trail_size_modifier.is_valid()) { - code += " if (trail_divisor > 1) { base_scale *= textureLod(trail_size_modifier,vec2(float(int(NUMBER)%trail_divisor)/float(trail_divisor-1),0.0),0.0).r; } \n"; - } - - code += " TRANSFORM[0].xyz *= base_scale;\n"; - code += " TRANSFORM[1].xyz *= base_scale;\n"; - code += " TRANSFORM[2].xyz *= base_scale;\n"; - if (flags[FLAG_DISABLE_Z]) { - code += " VELOCITY.z = 0.0;\n"; - code += " TRANSFORM[3].z = 0.0;\n"; - } - code += "}\n"; - code += "\n"; - - ShaderData shader_data; - shader_data.shader = VS::get_singleton()->shader_create(); - shader_data.users = 1; - - VS::get_singleton()->shader_set_code(shader_data.shader, code); - - shader_map[mk] = shader_data; - - VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); -} - -void ParticlesMaterial::flush_changes() { - - if (material_mutex) - material_mutex->lock(); - - while (dirty_materials.first()) { - - dirty_materials.first()->self()->_update_shader(); - } - - if (material_mutex) - material_mutex->unlock(); -} - -void ParticlesMaterial::_queue_shader_change() { - - if (material_mutex) - material_mutex->lock(); - - if (!element.in_list()) { - dirty_materials.add(&element); - } - - if (material_mutex) - material_mutex->unlock(); -} - -bool ParticlesMaterial::_is_shader_dirty() const { - - bool dirty = false; - - if (material_mutex) - material_mutex->lock(); - - dirty = element.in_list(); - - if (material_mutex) - material_mutex->unlock(); - - return dirty; -} - -void ParticlesMaterial::set_spread(float p_spread) { - - spread = p_spread; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread); -} - -float ParticlesMaterial::get_spread() const { - - return spread; -} - -void ParticlesMaterial::set_flatness(float p_flatness) { - - flatness = p_flatness; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness); -} -float ParticlesMaterial::get_flatness() const { - - return flatness; -} - -void ParticlesMaterial::set_param(Parameter p_param, float p_value) { - - ERR_FAIL_INDEX(p_param, PARAM_MAX); - - parameters[p_param] = p_value; - - switch (p_param) { - case PARAM_INITIAL_LINEAR_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value); - } break; - case PARAM_ANGULAR_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value); - } break; - case PARAM_ORBIT_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value); - } break; - case PARAM_LINEAR_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value); - } break; - case PARAM_RADIAL_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value); - } break; - case PARAM_TANGENTIAL_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value); - } break; - case PARAM_DAMPING: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value); - } break; - case PARAM_ANGLE: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value); - } break; - case PARAM_SCALE: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value); - } break; - case PARAM_HUE_VARIATION: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value); - } break; - case PARAM_ANIM_SPEED: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value); - } break; - case PARAM_ANIM_OFFSET: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value); - } break; - } -} -float ParticlesMaterial::get_param(Parameter p_param) const { - - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - - return parameters[p_param]; -} - -void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) { - - ERR_FAIL_INDEX(p_param, PARAM_MAX); - - randomness[p_param] = p_value; - - switch (p_param) { - case PARAM_INITIAL_LINEAR_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value); - } break; - case PARAM_ANGULAR_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value); - } break; - case PARAM_ORBIT_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value); - } break; - case PARAM_LINEAR_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value); - } break; - case PARAM_RADIAL_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value); - } break; - case PARAM_TANGENTIAL_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value); - } break; - case PARAM_DAMPING: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value); - } break; - case PARAM_ANGLE: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value); - } break; - case PARAM_SCALE: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value); - } break; - case PARAM_HUE_VARIATION: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value); - } break; - case PARAM_ANIM_SPEED: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value); - } break; - case PARAM_ANIM_OFFSET: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value); - } break; - } -} -float ParticlesMaterial::get_param_randomness(Parameter p_param) const { - - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - - return randomness[p_param]; -} - -static void _adjust_curve_range(const Ref<Texture> &p_texture, float p_min, float p_max) { - - Ref<CurveTexture> curve_tex = p_texture; - if (!curve_tex.is_valid()) - return; - - curve_tex->ensure_default_setup(p_min, p_max); -} - -void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> &p_texture) { - - ERR_FAIL_INDEX(p_param, PARAM_MAX); - - tex_parameters[p_param] = p_texture; - - switch (p_param) { - case PARAM_INITIAL_LINEAR_VELOCITY: { - //do none for this one - } break; - case PARAM_ANGULAR_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture); - _adjust_curve_range(p_texture, -360, 360); - } break; - case PARAM_ORBIT_VELOCITY: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture); - _adjust_curve_range(p_texture, -500, 500); - } break; - case PARAM_LINEAR_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture); - _adjust_curve_range(p_texture, -200, 200); - } break; - case PARAM_RADIAL_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture); - _adjust_curve_range(p_texture, -200, 200); - } break; - case PARAM_TANGENTIAL_ACCEL: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture); - _adjust_curve_range(p_texture, -200, 200); - } break; - case PARAM_DAMPING: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture); - _adjust_curve_range(p_texture, 0, 100); - } break; - case PARAM_ANGLE: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture); - _adjust_curve_range(p_texture, -360, 360); - } break; - case PARAM_SCALE: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture); - - Ref<CurveTexture> curve_tex = p_texture; - if (curve_tex.is_valid()) { - curve_tex->ensure_default_setup(); - } - - } break; - case PARAM_HUE_VARIATION: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture); - _adjust_curve_range(p_texture, -1, 1); - } break; - case PARAM_ANIM_SPEED: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture); - _adjust_curve_range(p_texture, 0, 200); - } break; - case PARAM_ANIM_OFFSET: { - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); - } break; - } - - _queue_shader_change(); -} -Ref<Texture> ParticlesMaterial::get_param_texture(Parameter p_param) const { - - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture>()); - - return tex_parameters[p_param]; -} - -void ParticlesMaterial::set_color(const Color &p_color) { - - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color); - color = p_color; -} - -Color ParticlesMaterial::get_color() const { - - return color; -} - -void ParticlesMaterial::set_color_ramp(const Ref<Texture> &p_texture) { - - color_ramp = p_texture; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture); - _queue_shader_change(); - _change_notify(); -} - -Ref<Texture> ParticlesMaterial::get_color_ramp() const { - - return color_ramp; -} - -void ParticlesMaterial::set_flag(Flags p_flag, bool p_enable) { - ERR_FAIL_INDEX(p_flag, FLAG_MAX); - flags[p_flag] = p_enable; - _queue_shader_change(); - if (p_flag == FLAG_DISABLE_Z) { - _change_notify(); - } -} - -bool ParticlesMaterial::get_flag(Flags p_flag) const { - ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); - return flags[p_flag]; -} - -void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { - - emission_shape = p_shape; - _change_notify(); - _queue_shader_change(); -} - -void ParticlesMaterial::set_emission_sphere_radius(float p_radius) { - - emission_sphere_radius = p_radius; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius); -} - -void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { - - emission_box_extents = p_extents; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents); -} - -void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) { - - emission_point_texture = p_points; - 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; - 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; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors); - _queue_shader_change(); -} - -void ParticlesMaterial::set_emission_point_count(int p_count) { - - emission_point_count = p_count; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count); -} - -ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const { - - return emission_shape; -} - -float ParticlesMaterial::get_emission_sphere_radius() const { - - return emission_sphere_radius; -} -Vector3 ParticlesMaterial::get_emission_box_extents() const { - - return emission_box_extents; -} -Ref<Texture> ParticlesMaterial::get_emission_point_texture() const { - - return emission_point_texture; -} -Ref<Texture> ParticlesMaterial::get_emission_normal_texture() const { - - return emission_normal_texture; -} - -Ref<Texture> ParticlesMaterial::get_emission_color_texture() const { - - return emission_color_texture; -} - -int ParticlesMaterial::get_emission_point_count() const { - - return emission_point_count; -} - -void ParticlesMaterial::set_trail_divisor(int p_divisor) { - - trail_divisor = p_divisor; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor); -} - -int ParticlesMaterial::get_trail_divisor() const { - - return trail_divisor; -} - -void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) { - - trail_size_modifier = p_trail_size_modifier; - - Ref<CurveTexture> curve = trail_size_modifier; - if (curve.is_valid()) { - curve->ensure_default_setup(); - } - - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve); - _queue_shader_change(); -} - -Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const { - - return trail_size_modifier; -} - -void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) { - - trail_color_modifier = p_trail_color_modifier; - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier); - _queue_shader_change(); -} - -Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const { - - return trail_color_modifier; -} - -void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) { - - gravity = p_gravity; - Vector3 gset = gravity; - if (gset == Vector3()) { - gset = Vector3(0, -0.000001, 0); //as gravity is used as upvector in some calculations - } - VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset); -} - -Vector3 ParticlesMaterial::get_gravity() const { - - return gravity; -} - -RID ParticlesMaterial::get_shader_rid() const { - - ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); - return shader_map[current_key].shader; -} - -void ParticlesMaterial::_validate_property(PropertyInfo &property) const { - - if (property.name == "color" && color_ramp.is_valid()) { - property.usage = 0; - } - - if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { - property.usage = 0; - } - - if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - property.usage = 0; - } - - if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = 0; - } - - if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; - } - - if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - property.usage = 0; - } - - if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { - property.usage = 0; - } -} - -Shader::Mode ParticlesMaterial::get_shader_mode() const { - - return Shader::MODE_PARTICLES; -} - -void ParticlesMaterial::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread); - ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread); - - ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness); - ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness); - - ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ParticlesMaterial::set_param); - ClassDB::bind_method(D_METHOD("get_param", "param"), &ParticlesMaterial::get_param); - - ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &ParticlesMaterial::set_param_randomness); - ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &ParticlesMaterial::get_param_randomness); - - ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture); - ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture); - - ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color); - ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color); - - ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp); - ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp); - - ClassDB::bind_method(D_METHOD("set_flag", "flag", "enable"), &ParticlesMaterial::set_flag); - ClassDB::bind_method(D_METHOD("get_flag", "flag"), &ParticlesMaterial::get_flag); - - ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape); - ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape); - - ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius); - ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius); - - ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents); - ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents); - - ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture); - ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture); - - ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture); - ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture); - - ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture); - ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture); - - ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count); - ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count); - - ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor); - ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor); - - ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture"), &ParticlesMaterial::set_trail_size_modifier); - ClassDB::bind_method(D_METHOD("get_trail_size_modifier"), &ParticlesMaterial::get_trail_size_modifier); - - ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture"), &ParticlesMaterial::set_trail_color_modifier); - ClassDB::bind_method(D_METHOD("get_trail_color_modifier"), &ParticlesMaterial::get_trail_color_modifier); - - ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity); - ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity); - - ADD_GROUP("Trail", "trail_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier"); - ADD_GROUP("Emission Shape", "emission_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "emission_box_extents"), "set_emission_box_extents", "get_emission_box_extents"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_point_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_point_texture", "get_emission_point_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_normal_texture", "get_emission_normal_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "emission_color_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_emission_color_texture", "get_emission_color_texture"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_point_count", PROPERTY_HINT_RANGE, "0,1000000,1"), "set_emission_point_count", "get_emission_point_count"); - ADD_GROUP("Flags", "flag_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_align_y"), "set_flag", "get_flag", FLAG_ALIGN_Y_TO_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_rotate_y"), "set_flag", "get_flag", FLAG_ROTATE_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flag_disable_z"), "set_flag", "get_flag", FLAG_DISABLE_Z); - ADD_GROUP("Spread", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "flatness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_flatness", "get_flatness"); - ADD_GROUP("Gravity", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); - ADD_GROUP("Initial Velocity", "initial_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY); - ADD_GROUP("Angular Velocity", "angular_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY); - ADD_GROUP("Orbit Velocity", "orbit_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY); - ADD_GROUP("Linear Accel", "linear_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL); - ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL); - ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL); - ADD_GROUP("Damping", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); - ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); - ADD_GROUP("Scale", ""); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE); - ADD_GROUP("Color", ""); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp"); - - ADD_GROUP("Hue Variation", "hue_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.1"), "set_param", "get_param", PARAM_HUE_VARIATION); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION); - ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anim_loop"), "set_flag", "get_flag", FLAG_ANIM_LOOP); - - BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY); - BIND_ENUM_CONSTANT(PARAM_LINEAR_ACCEL); - BIND_ENUM_CONSTANT(PARAM_RADIAL_ACCEL); - BIND_ENUM_CONSTANT(PARAM_TANGENTIAL_ACCEL); - BIND_ENUM_CONSTANT(PARAM_DAMPING); - BIND_ENUM_CONSTANT(PARAM_ANGLE); - BIND_ENUM_CONSTANT(PARAM_SCALE); - BIND_ENUM_CONSTANT(PARAM_HUE_VARIATION); - BIND_ENUM_CONSTANT(PARAM_ANIM_SPEED); - BIND_ENUM_CONSTANT(PARAM_ANIM_OFFSET); - BIND_ENUM_CONSTANT(PARAM_MAX); - - BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); - BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); - BIND_ENUM_CONSTANT(FLAG_MAX); - - BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_BOX); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); -} - -ParticlesMaterial::ParticlesMaterial() : - element(this) { - - set_spread(45); - set_flatness(0); - set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); - set_param(PARAM_ORBIT_VELOCITY, 0); - set_param(PARAM_LINEAR_ACCEL, 0); - set_param(PARAM_RADIAL_ACCEL, 0); - set_param(PARAM_TANGENTIAL_ACCEL, 0); - set_param(PARAM_DAMPING, 0); - set_param(PARAM_ANGLE, 0); - set_param(PARAM_SCALE, 1); - set_param(PARAM_HUE_VARIATION, 0); - set_param(PARAM_ANIM_SPEED, 0); - set_param(PARAM_ANIM_OFFSET, 0); - set_emission_shape(EMISSION_SHAPE_POINT); - set_emission_sphere_radius(1); - set_emission_box_extents(Vector3(1, 1, 1)); - set_trail_divisor(1); - set_gravity(Vector3(0, -9.8, 0)); - emission_point_count = 1; - - for (int i = 0; i < PARAM_MAX; i++) { - set_param_randomness(Parameter(i), 0); - } - - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; - } - - set_color(Color(1, 1, 1, 1)); - - current_key.key = 0; - current_key.invalid_key = 1; - - _queue_shader_change(); -} - -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/particles.h b/scene/3d/particles.h index 17e21c6cee..742246f78c 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -28,12 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VISUALINSTANCEPARTICLES_H -#define VISUALINSTANCEPARTICLES_H +#ifndef PARTICLES_H +#define PARTICLES_H #include "rid.h" #include "scene/3d/visual_instance.h" -#include "scene/main/timer.h" #include "scene/resources/material.h" /** @@ -135,269 +134,4 @@ public: VARIANT_ENUM_CAST(Particles::DrawOrder) -class ParticlesMaterial : public Material { - - GDCLASS(ParticlesMaterial, Material) - -public: - enum Parameter { - - PARAM_INITIAL_LINEAR_VELOCITY, - PARAM_ANGULAR_VELOCITY, - PARAM_ORBIT_VELOCITY, - PARAM_LINEAR_ACCEL, - PARAM_RADIAL_ACCEL, - PARAM_TANGENTIAL_ACCEL, - PARAM_DAMPING, - PARAM_ANGLE, - PARAM_SCALE, - PARAM_HUE_VARIATION, - PARAM_ANIM_SPEED, - PARAM_ANIM_OFFSET, - PARAM_MAX - }; - - enum Flags { - FLAG_ALIGN_Y_TO_VELOCITY, - FLAG_ROTATE_Y, - FLAG_DISABLE_Z, - FLAG_ANIM_LOOP, - FLAG_MAX - }; - - enum EmissionShape { - EMISSION_SHAPE_POINT, - EMISSION_SHAPE_SPHERE, - EMISSION_SHAPE_BOX, - EMISSION_SHAPE_POINTS, - EMISSION_SHAPE_DIRECTED_POINTS, - }; - -private: - union MaterialKey { - - struct { - uint32_t texture_mask : 16; - uint32_t texture_color : 1; - uint32_t flags : 4; - uint32_t emission_shape : 2; - uint32_t trail_size_texture : 1; - uint32_t trail_color_texture : 1; - uint32_t invalid_key : 1; - uint32_t has_emission_color : 1; - }; - - uint32_t key; - - bool operator<(const MaterialKey &p_key) const { - return key < p_key.key; - } - }; - - struct ShaderData { - RID shader; - int users; - }; - - static Map<MaterialKey, ShaderData> shader_map; - - MaterialKey current_key; - - _FORCE_INLINE_ MaterialKey _compute_key() const { - - MaterialKey mk; - mk.key = 0; - for (int i = 0; i < PARAM_MAX; i++) { - if (tex_parameters[i].is_valid()) { - mk.texture_mask |= (1 << i); - } - } - for (int i = 0; i < FLAG_MAX; i++) { - if (flags[i]) { - mk.flags |= (1 << i); - } - } - - mk.texture_color = color_ramp.is_valid() ? 1 : 0; - mk.emission_shape = emission_shape; - mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0; - mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0; - mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid(); - - return mk; - } - - static Mutex *material_mutex; - static SelfList<ParticlesMaterial>::List dirty_materials; - - struct ShaderNames { - StringName spread; - StringName flatness; - StringName initial_linear_velocity; - StringName initial_angle; - StringName angular_velocity; - StringName orbit_velocity; - StringName linear_accel; - StringName radial_accel; - StringName tangent_accel; - StringName damping; - StringName scale; - StringName hue_variation; - StringName anim_speed; - StringName anim_offset; - - StringName initial_linear_velocity_random; - StringName initial_angle_random; - StringName angular_velocity_random; - StringName orbit_velocity_random; - StringName linear_accel_random; - StringName radial_accel_random; - StringName tangent_accel_random; - StringName damping_random; - StringName scale_random; - StringName hue_variation_random; - StringName anim_speed_random; - StringName anim_offset_random; - - StringName angle_texture; - StringName angular_velocity_texture; - StringName orbit_velocity_texture; - StringName linear_accel_texture; - StringName radial_accel_texture; - StringName tangent_accel_texture; - StringName damping_texture; - StringName scale_texture; - StringName hue_variation_texture; - StringName anim_speed_texture; - StringName anim_offset_texture; - - StringName color; - StringName color_ramp; - - StringName emission_sphere_radius; - StringName emission_box_extents; - StringName emission_texture_point_count; - StringName emission_texture_points; - StringName emission_texture_normal; - StringName emission_texture_color; - - StringName trail_divisor; - StringName trail_size_modifier; - StringName trail_color_modifier; - - StringName gravity; - }; - - static ShaderNames *shader_names; - - SelfList<ParticlesMaterial> element; - - void _update_shader(); - _FORCE_INLINE_ void _queue_shader_change(); - _FORCE_INLINE_ bool _is_shader_dirty() const; - - float spread; - float flatness; - - float parameters[PARAM_MAX]; - float randomness[PARAM_MAX]; - - Ref<Texture> tex_parameters[PARAM_MAX]; - Color color; - Ref<Texture> color_ramp; - - bool flags[FLAG_MAX]; - - EmissionShape emission_shape; - float emission_sphere_radius; - Vector3 emission_box_extents; - Ref<Texture> emission_point_texture; - Ref<Texture> emission_normal_texture; - Ref<Texture> emission_color_texture; - int emission_point_count; - - bool anim_loop; - - int trail_divisor; - - Ref<CurveTexture> trail_size_modifier; - Ref<GradientTexture> trail_color_modifier; - - Vector3 gravity; - - //do not save emission points here - -protected: - static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const; - -public: - void set_spread(float p_spread); - float get_spread() const; - - void set_flatness(float p_flatness); - float get_flatness() const; - - void set_param(Parameter p_param, float p_value); - float get_param(Parameter p_param) const; - - void set_param_randomness(Parameter p_param, float p_value); - float get_param_randomness(Parameter p_param) const; - - void set_param_texture(Parameter p_param, const Ref<Texture> &p_texture); - Ref<Texture> get_param_texture(Parameter p_param) const; - - void set_color(const Color &p_color); - Color get_color() const; - - void set_color_ramp(const Ref<Texture> &p_texture); - Ref<Texture> get_color_ramp() const; - - void set_flag(Flags p_flag, bool p_enable); - bool get_flag(Flags p_flag) const; - - void set_emission_shape(EmissionShape p_shape); - void set_emission_sphere_radius(float p_radius); - void set_emission_box_extents(Vector3 p_extents); - void set_emission_point_texture(const Ref<Texture> &p_points); - void set_emission_normal_texture(const Ref<Texture> &p_normals); - void set_emission_color_texture(const Ref<Texture> &p_colors); - void set_emission_point_count(int p_count); - - EmissionShape get_emission_shape() const; - float get_emission_sphere_radius() const; - Vector3 get_emission_box_extents() const; - Ref<Texture> get_emission_point_texture() const; - Ref<Texture> get_emission_normal_texture() const; - Ref<Texture> get_emission_color_texture() const; - int get_emission_point_count() const; - - void set_trail_divisor(int p_divisor); - int get_trail_divisor() const; - - void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier); - Ref<CurveTexture> get_trail_size_modifier() const; - - void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier); - Ref<GradientTexture> get_trail_color_modifier() const; - - void set_gravity(const Vector3 &p_gravity); - Vector3 get_gravity() const; - - static void init_shaders(); - static void finish_shaders(); - static void flush_changes(); - - RID get_shader_rid() const; - - virtual Shader::Mode get_shader_mode() const; - - ParticlesMaterial(); - ~ParticlesMaterial(); -}; - -VARIANT_ENUM_CAST(ParticlesMaterial::Parameter) -VARIANT_ENUM_CAST(ParticlesMaterial::Flags) -VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape) - -#endif +#endif // PARTICLES_H diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 5056fb2fe4..f7af6a57dd 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -30,6 +30,7 @@ #include "physics_body.h" +#include "core/core_string_names.h" #include "engine.h" #include "method_bind_ext.gen.inc" #include "scene/scene_string_names.h" @@ -39,17 +40,6 @@ #endif void PhysicsBody::_notification(int p_what) { - - /* - switch(p_what) { - - case NOTIFICATION_TRANSFORM_CHANGED: { - - PhysicsServer::get_singleton()->body_set_state(get_rid(),PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); - - } break; - } - */ } Vector3 PhysicsBody::get_linear_velocity() const { @@ -121,23 +111,23 @@ bool PhysicsBody::get_collision_layer_bit(int p_bit) const { void PhysicsBody::add_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); - PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node); - if (!physics_body) { - ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type"); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); } - ERR_FAIL_COND(!physics_body); - PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid()); + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid()); } void PhysicsBody::remove_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); - PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node); - if (!physics_body) { - ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type"); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); } - ERR_FAIL_COND(!physics_body); - PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid()); + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } void PhysicsBody::_set_layers(uint32_t p_mask) { @@ -178,28 +168,84 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : collision_mask = 1; } +#ifndef DISABLE_DEPRECATED void StaticBody::set_friction(real_t p_friction) { + if (p_friction == 1.0) { // default value, don't create an override for that + return; + } + + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + 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); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + set_physics_material_override(physics_material_override); + } + physics_material_override->set_friction(p_friction); } + real_t StaticBody::get_friction() const { - return friction; + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 1; + } + + return physics_material_override->get_friction(); } void StaticBody::set_bounce(real_t p_bounce) { + if (p_bounce == 0.0) { // default value, don't create an override for that + return; + } + + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + 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); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + set_physics_material_override(physics_material_override); + } + physics_material_override->set_bounce(p_bounce); } + real_t StaticBody::get_bounce() const { - return bounce; + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 0; + } + + return physics_material_override->get_bounce(); +} +#endif + +void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> StaticBody::get_physics_material_override() const { + return physics_material_override; } void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) { @@ -230,30 +276,45 @@ void StaticBody::_bind_methods() { ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody::get_constant_linear_velocity); ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody::get_constant_angular_velocity); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_friction", "friction"), &StaticBody::set_friction); ClassDB::bind_method(D_METHOD("get_friction"), &StaticBody::get_friction); ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce); ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce); +#endif // DISABLE_DEPRECATED + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with); - 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"); - +#ifndef DISABLE_DEPRECATED + ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction"); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce"); +#endif // DISABLE_DEPRECATED + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); } StaticBody::StaticBody() : PhysicsBody(PhysicsServer::BODY_MODE_STATIC) { - - bounce = 0; - friction = 1; } -StaticBody::~StaticBody() { +StaticBody::~StaticBody() {} + +void StaticBody::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } } void RigidBody::_body_enter_tree(ObjectID p_id) { @@ -354,7 +415,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, 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); if (in_tree) - emit_signal(SceneStringNames::get_singleton()->body_exited, obj); + emit_signal(SceneStringNames::get_singleton()->body_exited, node); } contact_monitor->body_map.erase(E); @@ -550,28 +611,80 @@ real_t RigidBody::get_weight() const { return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)); } +#ifndef DISABLE_DEPRECATED void RigidBody::set_friction(real_t p_friction) { + if (p_friction == 1.0) { // default value, don't create an override for that + return; + } + + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + 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); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + set_physics_material_override(physics_material_override); + } + physics_material_override->set_friction(p_friction); } real_t RigidBody::get_friction() const { - return friction; + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 1; + } + + return physics_material_override->get_friction(); } void RigidBody::set_bounce(real_t p_bounce) { + if (p_bounce == 0.0) { // default value, don't create an override for that + return; + } + + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + 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); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + set_physics_material_override(physics_material_override); + } + physics_material_override->set_bounce(p_bounce); } real_t RigidBody::get_bounce() const { + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") + WARN_DEPRECATED + if (physics_material_override.is_null()) { + return 0; + } - return bounce; + return physics_material_override->get_bounce(); +} +#endif // DISABLE_DEPRECATED + +void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> RigidBody::get_physics_material_override() const { + return physics_material_override; } void RigidBody::set_gravity_scale(real_t p_gravity_scale) { @@ -693,6 +806,22 @@ int RigidBody::get_max_contacts_reported() const { return max_contacts_reported; } +void RigidBody::add_central_force(const Vector3 &p_force) { + PhysicsServer::get_singleton()->body_add_central_force(get_rid(), p_force); +} + +void RigidBody::add_force(const Vector3 &p_force, const Vector3 &p_pos) { + PhysicsServer::get_singleton()->body_add_force(get_rid(), p_force, p_pos); +} + +void RigidBody::add_torque(const Vector3 &p_torque) { + PhysicsServer::get_singleton()->body_add_torque(get_rid(), p_torque); +} + +void RigidBody::apply_central_impulse(const Vector3 &p_impulse) { + PhysicsServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); +} + void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) { PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); @@ -806,11 +935,18 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_weight", "weight"), &RigidBody::set_weight); ClassDB::bind_method(D_METHOD("get_weight"), &RigidBody::get_weight); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_friction", "friction"), &RigidBody::set_friction); ClassDB::bind_method(D_METHOD("get_friction"), &RigidBody::get_friction); ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce); ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce); +#endif // DISABLE_DEPRECATED + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody::_reload_physics_characteristics); ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity); ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity); @@ -840,6 +976,12 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody::is_using_continuous_collision_detection); ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity); + + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody::add_central_force); + ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody::add_force); + ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody::add_torque); + + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody::apply_central_impulse); 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); @@ -863,8 +1005,11 @@ void RigidBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode"); 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", PROPERTY_USAGE_EDITOR), "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"); +#ifndef DISABLE_DEPRECATED + ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_friction", "get_friction"); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_bounce", "get_bounce"); +#endif // DISABLE_DEPRECATED + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection"); @@ -886,10 +1031,10 @@ void RigidBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "-1,128,0.01"), "set_angular_damp", "get_angular_damp"); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); BIND_ENUM_CONSTANT(MODE_RIGID); @@ -903,9 +1048,7 @@ RigidBody::RigidBody() : mode = MODE_RIGID; - bounce = 0; mass = 1; - friction = 1; max_contacts_reported = 0; state = NULL; @@ -929,13 +1072,24 @@ RigidBody::~RigidBody() { if (contact_monitor) memdelete(contact_monitor); } + +void RigidBody::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } +} + ////////////////////////////////////////////////////// ////////////////////////// -Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia) { +Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_test_only) { Collision col; - if (move_and_collide(p_motion, p_infinite_inertia, col)) { + if (move_and_collide(p_motion, p_infinite_inertia, col, p_test_only)) { if (motion_cache.is_null()) { motion_cache.instance(); motion_cache->owner = this; @@ -949,7 +1103,7 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf return Ref<KinematicCollision>(); } -bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision) { +bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_test_only) { Transform gt = get_global_transform(); PhysicsServer::MotionResult result; @@ -962,6 +1116,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in r_collision.collision = result.collision_point; r_collision.normal = result.collision_normal; r_collision.collider = result.collider_id; + r_collision.collider_rid = result.collider; r_collision.travel = result.motion; r_collision.remainder = result.remainder; r_collision.local_shape = result.collision_local_shape; @@ -973,13 +1128,18 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in } } - gt.origin += result.motion; - set_global_transform(gt); + if (!p_test_only) { + gt.origin += result.motion; + set_global_transform(gt); + } return colliding; } -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) { +//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45. +#define FLOOR_ANGLE_THRESHOLD 0.01 + +Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector3 lv = p_linear_velocity; @@ -997,69 +1157,127 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve colliders.clear(); floor_velocity = Vector3(); + Vector3 lv_n = p_linear_velocity.normalized(); + while (p_max_slides) { Collision collision; - bool collided = move_and_collide(motion, p_infinite_inertia, collision); - - if (collided) { + bool found_collision = false; - motion = collision.remainder; + int test_type = 0; - if (p_floor_direction == Vector3()) { - //all is a wall - on_wall = true; + do { + bool collided; + if (test_type == 0) { //collide + collided = move_and_collide(motion, p_infinite_inertia, collision); + if (!collided) { + motion = Vector3(); //clear because no collision happened and motion completed + } } else { - if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor + collided = separate_raycast_shapes(p_infinite_inertia, collision); + if (collided) { + collision.remainder = motion; //keep + collision.travel = Vector3(); + } + } - on_floor = true; - floor_velocity = collision.collider_vel; + if (collided) { + found_collision = true; + } - Vector3 rel_v = lv - floor_velocity; - Vector3 hv = rel_v - p_floor_direction * p_floor_direction.dot(rel_v); + if (collided) { - if (collision.travel.length() < 0.05 && hv.length() < p_slope_stop_min_velocity) { - Transform gt = get_global_transform(); - gt.origin -= collision.travel; - set_global_transform(gt); - return floor_velocity - p_floor_direction * p_floor_direction.dot(floor_velocity); - } - } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling - on_ceiling = true; - } else { + colliders.push_back(collision); + motion = collision.remainder; + + bool is_on_slope = false; + if (p_floor_direction == Vector3()) { + //all is a wall on_wall = true; + } else { + if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor + + on_floor = true; + on_floor_body = collision.collider_rid; + floor_velocity = collision.collider_vel; + + if (p_stop_on_slope) { + if (Vector3() == lv_n + p_floor_direction) { + Transform gt = get_global_transform(); + gt.origin -= collision.travel; + set_global_transform(gt); + return Vector3(); + } + } + + is_on_slope = true; + + } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling + on_ceiling = true; + } else { + on_wall = true; + } } - } - Vector3 n = collision.normal; - motion = motion.slide(n); - lv = lv.slide(n); + if (p_stop_on_slope && is_on_slope) { + motion = motion.slide(p_floor_direction); + lv = lv.slide(p_floor_direction); + } else { + Vector3 n = collision.normal; + motion = motion.slide(n); + lv = lv.slide(n); + } - for (int i = 0; i < 3; i++) { - if (locked_axis & (1 << i)) { - lv[i] = 0; + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + lv[i] = 0; + } } } - colliders.push_back(collision); + ++test_type; + } while (!p_stop_on_slope && test_type < 2); - } else { + if (!found_collision || motion == Vector3()) break; - } - p_max_slides--; - if (motion == Vector3()) - break; + --p_max_slides; } return lv; } +Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction, bool p_infinite_inertia, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle) { + + bool was_on_floor = on_floor; + + Vector3 ret = move_and_slide(p_linear_velocity, p_floor_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); + if (!was_on_floor || p_snap == Vector3()) { + return ret; + } + + Collision col; + Transform gt = get_global_transform(); + + if (move_and_collide(p_snap, p_infinite_inertia, col, true)) { + gt.origin += col.travel; + if (p_floor_direction != Vector3() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + on_floor = true; + on_floor_body = col.collider_rid; + floor_velocity = col.collider_vel; + } + set_global_transform(gt); + } + + return ret; +} + bool KinematicBody::is_on_floor() const { return on_floor; } + bool KinematicBody::is_on_wall() const { return on_wall; @@ -1081,6 +1299,43 @@ bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia); } +bool KinematicBody::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) { + + PhysicsServer::SeparationResult sep_res[8]; //max 8 rays + + Transform gt = get_global_transform(); + + Vector3 recover; + int hits = PhysicsServer::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); + int deepest = -1; + float deepest_depth; + for (int i = 0; i < hits; i++) { + if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) { + deepest = i; + deepest_depth = sep_res[i].collision_depth; + } + } + + gt.origin += recover; + set_global_transform(gt); + + if (deepest != -1) { + r_collision.collider = sep_res[deepest].collider_id; + r_collision.collider_metadata = sep_res[deepest].collider_metadata; + r_collision.collider_shape = sep_res[deepest].collider_shape; + r_collision.collider_vel = sep_res[deepest].collider_velocity; + r_collision.collision = sep_res[deepest].collision_point; + r_collision.normal = sep_res[deepest].collision_normal; + r_collision.local_shape = sep_res[deepest].collision_local_shape; + r_collision.travel = recover; + r_collision.remainder = Vector3(); + + return true; + } else { + return false; + } +} + void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) { PhysicsServer::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); } @@ -1117,18 +1372,19 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) { } if (slide_colliders[p_bounce].is_null()) { - slide_colliders[p_bounce].instance(); - slide_colliders[p_bounce]->owner = this; + slide_colliders.write[p_bounce].instance(); + slide_colliders.write[p_bounce]->owner = this; } - slide_colliders[p_bounce]->collision = colliders[p_bounce]; + slide_colliders.write[p_bounce]->collision = colliders[p_bounce]; return slide_colliders[p_bounce]; } void KinematicBody::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody::_move, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "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("move_and_collide", "rel_vec", "infinite_inertia", "test_only"), &KinematicBody::_move, DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "floor_normal", "infinite_inertia", "stop_on_slope", "max_bounces", "floor_max_angle"), &KinematicBody::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move); @@ -1146,13 +1402,9 @@ void KinematicBody::_bind_methods() { ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody::get_slide_count); ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody::_get_slide_collision); - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_ANGULAR_Z); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_x", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_y", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "move_lock_z", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_axis_lock", "get_axis_lock", PhysicsServer::BODY_AXIS_LINEAR_Z); ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); } @@ -1174,7 +1426,7 @@ KinematicBody::~KinematicBody() { for (int i = 0; i < slide_colliders.size(); i++) { if (slide_colliders[i].is_valid()) { - slide_colliders[i]->owner = NULL; + slide_colliders.write[i]->owner = NULL; } } } @@ -1893,6 +2145,8 @@ void PhysicalBone::_bind_methods() { ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); + ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone::get_bone_id); + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass); @@ -2228,6 +2482,7 @@ void PhysicalBone::set_bounce(real_t p_bounce) { bounce = p_bounce; PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce); } + real_t PhysicalBone::get_bounce() const { return bounce; diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 17d2769c79..c4db41f577 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -32,6 +32,7 @@ #define PHYSICS_BODY__H #include "scene/3d/collision_object.h" +#include "scene/resources/physics_material.h" #include "servers/physics_server.h" #include "skeleton.h" #include "vset.h" @@ -81,18 +82,22 @@ class StaticBody : public PhysicsBody { Vector3 constant_linear_velocity; Vector3 constant_angular_velocity; - real_t bounce; - real_t friction; + Ref<PhysicsMaterial> physics_material_override; protected: static void _bind_methods(); public: +#ifndef DISABLE_DEPRECATED void set_friction(real_t p_friction); real_t get_friction() const; void set_bounce(real_t p_bounce); real_t get_bounce() const; +#endif + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; void set_constant_linear_velocity(const Vector3 &p_vel); void set_constant_angular_velocity(const Vector3 &p_vel); @@ -102,6 +107,9 @@ public: StaticBody(); ~StaticBody(); + +private: + void _reload_physics_characteristics(); }; class RigidBody : public PhysicsBody { @@ -121,9 +129,8 @@ protected: PhysicsDirectBodyState *state; Mode mode; - real_t bounce; real_t mass; - real_t friction; + Ref<PhysicsMaterial> physics_material_override; Vector3 linear_velocity; Vector3 angular_velocity; @@ -196,11 +203,16 @@ public: void set_weight(real_t p_weight); real_t get_weight() const; +#ifndef DISABLE_DEPRECATED void set_friction(real_t p_friction); real_t get_friction() const; void set_bounce(real_t p_bounce); real_t get_bounce() const; +#endif + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; void set_linear_velocity(const Vector3 &p_velocity); Vector3 get_linear_velocity() const; @@ -242,6 +254,11 @@ public: Array get_colliding_bodies() const; + void add_central_force(const Vector3 &p_force); + void add_force(const Vector3 &p_force, const Vector3 &p_pos); + void add_torque(const Vector3 &p_torque); + + void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); void apply_torque_impulse(const Vector3 &p_impulse); @@ -249,6 +266,9 @@ public: RigidBody(); ~RigidBody(); + +private: + void _reload_physics_characteristics(); }; VARIANT_ENUM_CAST(RigidBody::Mode); @@ -265,6 +285,7 @@ public: Vector3 normal; Vector3 collider_vel; ObjectID collider; + RID collider_rid; int collider_shape; Variant collider_metadata; Vector3 remainder; @@ -278,6 +299,7 @@ private: float margin; Vector3 floor_velocity; + RID on_floor_body; bool on_floor; bool on_ceiling; bool on_wall; @@ -287,23 +309,26 @@ private: _FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const; - Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true); + Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_test_only = false); Ref<KinematicCollision> _get_slide_collision(int p_bounce); protected: static void _bind_methods(); public: - bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision); + bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collisionz, bool p_test_only = false); bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia); + bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision); + void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const; void set_safe_margin(float p_margin); float get_safe_margin() const; - Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), 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)); + Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45)); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; @@ -537,6 +562,7 @@ protected: private: static Skeleton *find_skeleton_parent(Node *p_parent); + void _fix_joint_offset(); void _reload_joint(); diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index b2d10006f7..a30fc0ac3e 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -48,18 +48,14 @@ void Joint::_update_joint(bool p_only_free) { Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; - if (!node_a || !node_b) - return; - PhysicsBody *body_a = Object::cast_to<PhysicsBody>(node_a); PhysicsBody *body_b = Object::cast_to<PhysicsBody>(node_b); - if (!body_a || !body_b) - return; - - if (!body_a) { + if (!body_a && body_b) SWAP(body_a, body_b); - } + + if (!body_a) + return; joint = _configure_joint(body_a, body_b); @@ -69,7 +65,8 @@ void Joint::_update_joint(bool p_only_free) { PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority); ba = body_a->get_rid(); - bb = body_b->get_rid(); + if (body_b) + bb = body_b->get_rid(); PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } @@ -154,8 +151,8 @@ void Joint::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint::set_exclude_nodes_from_collision); ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint::get_exclude_nodes_from_collision); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a"), "set_node_a", "get_node_a"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b"), "set_node_b", "get_node_b"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_a", "get_node_a"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject"), "set_node_b", "get_node_b"); ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision"); @@ -260,7 +257,7 @@ void HingeJoint::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint::_set_lower_limit); ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint::_get_lower_limit); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT); ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit"); @@ -270,7 +267,7 @@ void HingeJoint::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE); BIND_ENUM_CONSTANT(PARAM_BIAS); diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index 7f83e2c3ea..b846a5b6c0 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -208,7 +208,7 @@ void RayCast::_update_raycast_state() { PhysicsDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask)) { + if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) { collided = true; against = rr.collider_id; @@ -259,6 +259,26 @@ void RayCast::clear_exceptions() { exclude.clear(); } +void RayCast::set_collide_with_areas(bool p_clip) { + + collide_with_areas = p_clip; +} + +bool RayCast::is_collide_with_areas_enabled() const { + + return collide_with_areas; +} + +void RayCast::set_collide_with_bodies(bool p_clip) { + + collide_with_bodies = p_clip; +} + +bool RayCast::is_collide_with_bodies_enabled() const { + + return collide_with_bodies; +} + void RayCast::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &RayCast::set_enabled); @@ -292,10 +312,20 @@ void RayCast::_bind_methods() { ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast::set_exclude_parent_body); ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast::get_exclude_parent_body); + ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &RayCast::set_collide_with_areas); + ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &RayCast::is_collide_with_areas_enabled); + + ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast::set_collide_with_bodies); + ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast::is_collide_with_bodies_enabled); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cast_to"), "set_cast_to", "get_cast_to"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ADD_GROUP("Collide With", "collide_with"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); } void RayCast::_create_debug_shape() { @@ -370,4 +400,6 @@ RayCast::RayCast() { cast_to = Vector3(0, -1, 0); debug_shape = NULL; exclude_parent_body = true; + collide_with_areas = false; + collide_with_bodies = true; } diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 20cea80700..e95382e1fe 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -45,7 +45,6 @@ class RayCast : public Spatial { Vector3 collision_normal; Vector3 cast_to; - Set<RID> exclude; uint32_t collision_mask; @@ -58,12 +57,21 @@ class RayCast : public Spatial { void _update_debug_shape(); void _clear_debug_shape(); + bool collide_with_areas; + bool collide_with_bodies; + protected: void _notification(int p_what); void _update_raycast_state(); static void _bind_methods(); public: + void set_collide_with_areas(bool p_clip); + bool is_collide_with_areas_enabled() const; + + void set_collide_with_bodies(bool p_clip); + bool is_collide_with_bodies_enabled() const; + void set_enabled(bool p_enabled); bool is_enabled() const; diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index 4d50945062..fe522bbe97 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -274,6 +274,7 @@ ReflectionProbe::ReflectionProbe() { probe = VisualServer::get_singleton()->reflection_probe_create(); VS::get_singleton()->instance_set_base(get_instance(), probe); + set_disable_scale(true); } ReflectionProbe::~ReflectionProbe() { diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp index afb85f7314..c12e49fb47 100644 --- a/scene/3d/remote_transform.cpp +++ b/scene/3d/remote_transform.cpp @@ -124,8 +124,10 @@ void RemoteTransform::_notification(int p_what) { void RemoteTransform::set_remote_node(const NodePath &p_remote_node) { remote_node = p_remote_node; - if (is_inside_tree()) + if (is_inside_tree()) { _update_cache(); + _update_remote(); + } update_configuration_warning(); } @@ -194,7 +196,7 @@ void RemoteTransform::_bind_methods() { ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale); ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path"), "set_remote_node", "get_remote_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates"); ADD_GROUP("Update", "update_"); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 76d90dc6ff..c796e47f25 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -66,7 +66,7 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { Array children = p_value; if (is_inside_tree()) { - bones[which].nodes_bound.clear(); + bones.write[which].nodes_bound.clear(); for (int i = 0; i < children.size(); i++) { @@ -131,7 +131,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const { String prep = "bones/" + itos(i) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, prep + "name")); - p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(i - 1) + ",1")); + p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1")); 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)); @@ -139,6 +139,59 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const { } } +void Skeleton::_update_process_order() { + + if (!process_order_dirty) + return; + + Bone *bonesptr = bones.ptrw(); + int len = bones.size(); + + process_order.resize(len); + int *order = process_order.ptrw(); + for (int i = 0; i < len; i++) { + + if (bonesptr[i].parent >= len) { + //validate this just in case + ERR_PRINTS("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent)); + bonesptr[i].parent = -1; + } + order[i] = i; + bonesptr[i].sort_index = i; + } + //now check process order + int pass_count = 0; + while (pass_count < len * len) { + //using bubblesort because of simplicity, it wont run every frame though. + //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic + bool swapped = false; + for (int i = 0; i < len; i++) { + int parent_idx = bonesptr[order[i]].parent; + if (parent_idx < 0) + continue; //do nothing because it has no parent + //swap indices + int parent_order = bonesptr[parent_idx].sort_index; + if (parent_order > i) { + bonesptr[order[i]].sort_index = parent_order; + bonesptr[parent_idx].sort_index = i; + //swap order + SWAP(order[i], order[parent_order]); + swapped = true; + } + } + + if (!swapped) + break; + pass_count++; + } + + if (pass_count == len * len) { + ERR_PRINT("Skeleton parenthood graph is cyclic"); + } + + process_order_dirty = false; +} + void Skeleton::_notification(int p_what) { switch (p_what) { @@ -176,24 +229,28 @@ void Skeleton::_notification(int p_what) { case NOTIFICATION_UPDATE_SKELETON: { VisualServer *vs = VisualServer::get_singleton(); - Bone *bonesptr = &bones[0]; + Bone *bonesptr = bones.ptrw(); int len = bones.size(); vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens + _update_process_order(); + + const int *order = process_order.ptr(); + // pose changed, rebuild cache of inverses if (rest_global_inverse_dirty) { // calculate global rests and invert them for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + Bone &b = bonesptr[order[i]]; if (b.parent >= 0) b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest; else b.rest_global_inverse = b.rest; } for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + Bone &b = bonesptr[order[i]]; b.rest_global_inverse.affine_invert(); } @@ -205,7 +262,7 @@ void Skeleton::_notification(int p_what) { for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + Bone &b = bonesptr[order[i]]; if (b.disable_rest) { if (b.enabled) { @@ -319,12 +376,13 @@ void Skeleton::add_bone(const String &p_name) { for (int i = 0; i < bones.size(); i++) { - ERR_FAIL_COND(bones[i].name == "p_name"); + ERR_FAIL_COND(bones[i].name == p_name); } Bone b; b.name = p_name; bones.push_back(b); + process_order_dirty = true; rest_global_inverse_dirty = true; _make_dirty(); @@ -368,10 +426,11 @@ int Skeleton::get_bone_count() const { void Skeleton::set_bone_parent(int p_bone, int p_parent) { ERR_FAIL_INDEX(p_bone, bones.size()); - ERR_FAIL_COND(p_parent != -1 && (p_parent < 0 || p_parent >= p_bone)); + ERR_FAIL_COND(p_parent != -1 && (p_parent < 0)); - bones[p_bone].parent = p_parent; + bones.write[p_bone].parent = p_parent; rest_global_inverse_dirty = true; + process_order_dirty = true; _make_dirty(); } @@ -379,21 +438,24 @@ void Skeleton::unparent_bone_and_rest(int p_bone) { ERR_FAIL_INDEX(p_bone, bones.size()); + _update_process_order(); + int parent = bones[p_bone].parent; while (parent >= 0) { - bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest; + bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest; parent = bones[parent].parent; } - bones[p_bone].parent = -1; - bones[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing + bones.write[p_bone].parent = -1; + bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing + process_order_dirty = true; _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; + bones.write[p_bone].ignore_animation = p_ignore; } bool Skeleton::is_bone_ignore_animation(int p_bone) const { @@ -405,7 +467,7 @@ bool Skeleton::is_bone_ignore_animation(int p_bone) const { void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].disable_rest = p_disable; + bones.write[p_bone].disable_rest = p_disable; } bool Skeleton::is_bone_rest_disabled(int p_bone) const { @@ -425,7 +487,7 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].rest = p_rest; + bones.write[p_bone].rest = p_rest; rest_global_inverse_dirty = true; _make_dirty(); } @@ -440,7 +502,7 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].enabled = p_enabled; + bones.write[p_bone].enabled = p_enabled; rest_global_inverse_dirty = true; _make_dirty(); } @@ -457,13 +519,13 @@ void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) { uint32_t id = p_node->get_instance_id(); - for (List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { + for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { if (E->get() == id) return; // already here } - bones[p_bone].nodes_bound.push_back(id); + bones.write[p_bone].nodes_bound.push_back(id); } void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) { @@ -471,7 +533,7 @@ void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) { ERR_FAIL_INDEX(p_bone, bones.size()); uint32_t id = p_node->get_instance_id(); - bones[p_bone].nodes_bound.erase(id); + bones.write[p_bone].nodes_bound.erase(id); } void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const { @@ -489,6 +551,8 @@ void Skeleton::clear_bones() { bones.clear(); rest_global_inverse_dirty = true; + process_order_dirty = true; + _make_dirty(); } @@ -499,7 +563,7 @@ void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) { ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(!is_inside_tree()); - bones[p_bone].pose = p_pose; + bones.write[p_bone].pose = p_pose; _make_dirty(); } Transform Skeleton::get_bone_pose(int p_bone) const { @@ -513,8 +577,8 @@ void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) ERR_FAIL_INDEX(p_bone, bones.size()); //ERR_FAIL_COND( !is_inside_scene() ); - bones[p_bone].custom_pose_enable = (p_custom_pose != Transform()); - bones[p_bone].custom_pose = p_custom_pose; + bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform()); + bones.write[p_bone].custom_pose = p_custom_pose; _make_dirty(); } @@ -538,27 +602,38 @@ void Skeleton::_make_dirty() { dirty = true; } +int Skeleton::get_process_order(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, bones.size(), -1); + _update_process_order(); + return process_order[p_idx]; +} + void Skeleton::localize_rests() { - for (int i = bones.size() - 1; i >= 0; i--) { + _update_process_order(); - if (bones[i].parent >= 0) - set_bone_rest(i, bones[bones[i].parent].rest.affine_inverse() * bones[i].rest); + for (int i = bones.size() - 1; i >= 0; i--) { + int idx = process_order[i]; + if (bones[idx].parent >= 0) { + set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest); + } } } +#ifndef _3D_DISABLED + 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; + bones.write[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; + bones.write[p_bone].physical_bone = NULL; _rebuild_physical_bones_cache(); } @@ -598,9 +673,12 @@ PhysicalBone *Skeleton::_get_physical_bone_parent(int p_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(); + PhysicalBone *parent_pb = _get_physical_bone_parent(i); + if (parent_pb != bones[i].physical_bone) { + bones.write[i].cache_parent_physical_bone = parent_pb; + if (bones[i].physical_bone) + bones[i].physical_bone->_on_bone_parent_changed(); + } } } @@ -658,7 +736,7 @@ void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { if (Variant::STRING == p_bones.get(i).get_type()) { int bone_id = find_bone(p_bones.get(i)); if (bone_id != -1) - sim_bones[c++] = bone_id; + sim_bones.write[c++] = bone_id; } } sim_bones.resize(c); @@ -691,6 +769,8 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) { _physical_bones_add_remove_collision_exception(false, this, p_exception); } +#endif // _3D_DISABLED + void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone); @@ -727,11 +807,17 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform); +#ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array())); 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); +#endif // _3D_DISABLED + + ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation); + BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); } @@ -739,6 +825,7 @@ Skeleton::Skeleton() { rest_global_inverse_dirty = true; dirty = false; + process_order_dirty = true; skeleton = VisualServer::get_singleton()->skeleton_create(); set_notify_transform(true); } diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index dad11960a5..e044e08437 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -38,7 +38,12 @@ @author Juan Linietsky <reduzio@gmail.com> */ +#ifndef _3D_DISABLED +typedef int BoneId; + class PhysicalBone; +#endif // _3D_DISABLED + class Skeleton : public Spatial { GDCLASS(Skeleton, Spatial); @@ -49,6 +54,7 @@ class Skeleton : public Spatial { bool enabled; int parent; + int sort_index; //used for re-sorting process order bool ignore_animation; @@ -64,8 +70,10 @@ class Skeleton : public Spatial { Transform transform_final; +#ifndef _3D_DISABLED PhysicalBone *physical_bone; PhysicalBone *cache_parent_physical_bone; +#endif // _3D_DISABLED List<uint32_t> nodes_bound; @@ -75,21 +83,25 @@ class Skeleton : public Spatial { ignore_animation = false; custom_pose_enable = false; disable_rest = false; +#ifndef _3D_DISABLED physical_bone = NULL; cache_parent_physical_bone = NULL; +#endif // _3D_DISABLED } }; bool rest_global_inverse_dirty; Vector<Bone> bones; + Vector<int> process_order; + bool process_order_dirty; RID skeleton; void _make_dirty(); bool dirty; - //bind helpers + // bind helpers Array _get_bound_child_nodes_to_bone(int p_bone) const { Array bound; @@ -103,6 +115,8 @@ class Skeleton : public Spatial { return bound; } + void _update_process_order(); + protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); @@ -163,7 +177,9 @@ public: Transform get_bone_custom_pose(int p_bone) const; void localize_rests(); // used for loaders and tools + int get_process_order(int p_idx); +#ifndef _3D_DISABLED // Physical bone API void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone); @@ -182,6 +198,7 @@ public: void physical_bones_start_simulation_on(const Array &p_bones); void physical_bones_add_collision_exception(RID p_exception); void physical_bones_remove_collision_exception(RID p_exception); +#endif // _3D_DISABLED public: Skeleton(); diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp new file mode 100644 index 0000000000..58ddb52760 --- /dev/null +++ b/scene/3d/soft_body.cpp @@ -0,0 +1,798 @@ +/*************************************************************************/ +/* soft_body.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "soft_body.h" +#include "os/os.h" +#include "scene/3d/collision_object.h" +#include "scene/3d/skeleton.h" +#include "servers/physics_server.h" + +SoftBodyVisualServerHandler::SoftBodyVisualServerHandler() {} + +void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) { + clear(); + + ERR_FAIL_COND(!p_mesh.is_valid()); + + mesh = p_mesh; + surface = p_surface; + + const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, surface); + const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface); + const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface); + uint32_t surface_offsets[VS::ARRAY_MAX]; + + buffer = VS::get_singleton()->mesh_surface_get_array(mesh, surface); + stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets); + offset_vertices = surface_offsets[VS::ARRAY_VERTEX]; + offset_normal = surface_offsets[VS::ARRAY_NORMAL]; +} + +void SoftBodyVisualServerHandler::clear() { + + if (mesh.is_valid()) { + buffer.resize(0); + } + + mesh = RID(); +} + +void SoftBodyVisualServerHandler::open() { + write_buffer = buffer.write(); +} + +void SoftBodyVisualServerHandler::close() { + write_buffer = PoolVector<uint8_t>::Write(); +} + +void SoftBodyVisualServerHandler::commit_changes() { + VS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer); +} + +void SoftBodyVisualServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) { + copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3); +} + +void SoftBodyVisualServerHandler::set_normal(int p_vertex_id, const void *p_vector3) { + copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3); +} + +void SoftBodyVisualServerHandler::set_aabb(const AABB &p_aabb) { + VS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb); +} + +SoftBody::PinnedPoint::PinnedPoint() : + point_index(-1), + spatial_attachment(NULL) { +} + +SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) { + point_index = obj_tocopy.point_index; + spatial_attachment_path = obj_tocopy.spatial_attachment_path; + spatial_attachment = obj_tocopy.spatial_attachment; + offset = obj_tocopy.offset; +} + +void SoftBody::_update_pickable() { + if (!is_inside_tree()) + return; + bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree(); + PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable); +} + +bool SoftBody::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + String which = name.get_slicec('/', 0); + + if ("pinned_points" == which) { + + return _set_property_pinned_points_indices(p_value); + + } else if ("attachments" == which) { + + int idx = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + + return _set_property_pinned_points_attachment(idx, what, p_value); + } + + return false; +} + +bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + String which = name.get_slicec('/', 0); + + if ("pinned_points" == which) { + Array arr_ret; + const int pinned_points_indices_size = pinned_points.size(); + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + arr_ret.resize(pinned_points_indices_size); + + for (int i = 0; i < pinned_points_indices_size; ++i) { + arr_ret[i] = r[i].point_index; + } + + r_ret = arr_ret; + return true; + + } else if ("attachments" == which) { + + int idx = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + + return _get_property_pinned_points(idx, what, r_ret); + } + + return false; +} + +void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const { + + const int pinned_points_indices_size = pinned_points.size(); + + p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points")); + + for (int i = 0; i < pinned_points_indices_size; ++i) { + p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index")); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path")); + p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset")); + } +} + +bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) { + + const int p_indices_size = p_indices.size(); + + { // Remove the pined points on physics server that will be removed by resize + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + if (p_indices_size < pinned_points.size()) { + for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) { + pin_point(r[i].point_index, false); + } + } + } + + pinned_points.resize(p_indices_size); + + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + int point_index; + for (int i = 0; i < p_indices_size; ++i) { + point_index = p_indices.get(i); + if (w[i].point_index != point_index) { + if (-1 != w[i].point_index) + pin_point(w[i].point_index, false); + w[i].point_index = point_index; + pin_point(w[i].point_index, true); + } + } + return true; +} + +bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) { + if (pinned_points.size() <= p_item) { + return false; + } + + if ("spatial_attachment_path" == p_what) { + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + pin_point(w[p_item].point_index, true, p_value); + _make_cache_dirty(); + } else if ("offset" == p_what) { + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + w[p_item].offset = p_value; + } else { + return false; + } + + return true; +} + +bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const { + if (pinned_points.size() <= p_item) { + return false; + } + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + + if ("point_index" == p_what) { + r_ret = r[p_item].point_index; + } else if ("spatial_attachment_path" == p_what) { + r_ret = r[p_item].spatial_attachment_path; + } else if ("offset" == p_what) { + r_ret = r[p_item].offset; + } else { + return false; + } + + return true; +} + +void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) { + update_physics_server(); + _reset_points_offsets(); +#ifdef TOOLS_ENABLED + if (p_changed == this) { + update_configuration_warning(); + } +#endif +} + +void SoftBody::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_WORLD: { + + if (Engine::get_singleton()->is_editor_hint()) { + + add_change_receptor(this); + } + + RID space = get_world()->get_space(); + PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space); + update_physics_server(); + } break; + case NOTIFICATION_READY: { + if (!parent_collision_ignore.is_empty()) + add_collision_exception_with(get_node(parent_collision_ignore)); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (Engine::get_singleton()->is_editor_hint()) { + _reset_points_offsets(); + return; + } + + PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); + + set_notify_transform(false); + // Required to be top level with Transform at center of world in order to modify VisualServer only to support custom Transform + set_as_toplevel(true); + set_transform(Transform()); + set_notify_transform(true); + + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + + if (!simulation_started) + return; + + _update_cache_pin_points_datas(); + // Submit bone attachment + const int pinned_points_indices_size = pinned_points.size(); + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + for (int i = 0; i < pinned_points_indices_size; ++i) { + if (r[i].spatial_attachment) { + PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); + } + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + + _update_pickable(); + + } break; + case NOTIFICATION_EXIT_WORLD: { + + PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, RID()); + + } break; + } + +#ifdef TOOLS_ENABLED + + if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warning(); + } + } + +#endif +} + +void SoftBody::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_draw_soft_mesh"), &SoftBody::_draw_soft_mesh); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody::get_collision_layer); + + ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody::set_collision_mask_bit); + ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody::get_collision_mask_bit); + + ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody::set_collision_layer_bit); + ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody::get_collision_layer_bit); + + ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore); + ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore); + + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with); + ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with); + + ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody::set_simulation_precision); + ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody::get_simulation_precision); + + ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody::set_total_mass); + ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody::get_total_mass); + + ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody::set_linear_stiffness); + ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody::get_linear_stiffness); + + ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody::set_areaAngular_stiffness); + ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody::get_areaAngular_stiffness); + + ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody::set_volume_stiffness); + ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody::get_volume_stiffness); + + ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody::set_pressure_coefficient); + ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody::get_pressure_coefficient); + + ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody::set_pose_matching_coefficient); + ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody::get_pose_matching_coefficient); + + ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody::set_damping_coefficient); + ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody::get_damping_coefficient); + + ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody::set_drag_coefficient); + ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody::get_drag_coefficient); + + ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody::set_ray_pickable); + ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody::is_ray_pickable); + + ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient"); +} + +String SoftBody::get_configuration_warning() const { + + String warning = MeshInstance::get_configuration_warning(); + + if (get_mesh().is_null()) { + if (!warning.empty()) + warning += "\n\n"; + + warning += TTR("This body will be ignored until you set a mesh"); + } + + Transform t = get_transform(); + if ((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 (!warning.empty()) + warning += "\n\n"; + + warning += TTR("Size changes to SoftBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); + } + + return warning; +} + +void SoftBody::_draw_soft_mesh() { + if (get_mesh().is_null()) + return; + + if (!visual_server_handler.is_ready()) { + + visual_server_handler.prepare(get_mesh()->get_rid(), 0); + + /// Necessary in order to render the mesh correctly (Soft body nodes are in global space) + simulation_started = true; + call_deferred("set_as_toplevel", true); + call_deferred("set_transform", Transform()); + } + + visual_server_handler.open(); + PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler); + visual_server_handler.close(); + + visual_server_handler.commit_changes(); +} + +void SoftBody::update_physics_server() { + + if (Engine::get_singleton()->is_editor_hint()) { + + if (get_mesh().is_valid()) + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); + else + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL); + + return; + } + + if (get_mesh().is_valid()) { + + become_mesh_owner(); + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); + VS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh"); + } else { + + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL); + VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh"); + } +} + +void SoftBody::become_mesh_owner() { + if (mesh.is_null()) + return; + + if (!mesh_owner) { + mesh_owner = true; + + Vector<Ref<Material> > copy_materials; + copy_materials.append_array(materials); + + ERR_FAIL_COND(!mesh->get_surface_count()); + + // Get current mesh array and create new mesh array with necessary flag for softbody + Array surface_arrays = mesh->surface_get_arrays(0); + Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0); + uint32_t surface_format = mesh->surface_get_format(0); + + surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL); + surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; + + Ref<ArrayMesh> soft_mesh; + soft_mesh.instance(); + soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format); + soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); + + set_mesh(soft_mesh); + + for (int i = copy_materials.size() - 1; 0 <= i; --i) { + set_surface_material(i, copy_materials[i]); + } + } +} + +void SoftBody::set_collision_mask(uint32_t p_mask) { + collision_mask = p_mask; + PhysicsServer::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask); +} + +uint32_t SoftBody::get_collision_mask() const { + return collision_mask; +} +void SoftBody::set_collision_layer(uint32_t p_layer) { + collision_layer = p_layer; + PhysicsServer::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer); +} + +uint32_t SoftBody::get_collision_layer() const { + return collision_layer; +} + +void SoftBody::set_collision_mask_bit(int p_bit, bool p_value) { + uint32_t mask = get_collision_mask(); + if (p_value) + mask |= 1 << p_bit; + else + mask &= ~(1 << p_bit); + set_collision_mask(mask); +} + +bool SoftBody::get_collision_mask_bit(int p_bit) const { + return get_collision_mask() & (1 << p_bit); +} + +void SoftBody::set_collision_layer_bit(int p_bit, bool p_value) { + uint32_t layer = get_collision_layer(); + if (p_value) + layer |= 1 << p_bit; + else + layer &= ~(1 << p_bit); + set_collision_layer(layer); +} + +bool SoftBody::get_collision_layer_bit(int p_bit) const { + return get_collision_layer() & (1 << p_bit); +} + +void SoftBody::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) { + parent_collision_ignore = p_parent_collision_ignore; +} + +const NodePath &SoftBody::get_parent_collision_ignore() const { + return parent_collision_ignore; +} + +void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) { + pinned_points = p_pinned_points_indices; + PoolVector<PinnedPoint>::Read w = pinned_points.read(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { + pin_point(p_pinned_points_indices[i].point_index, true); + } +} + +PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() { + return pinned_points; +} + +void SoftBody::add_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); + } + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid()); +} + +void SoftBody::remove_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); + } + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid()); +} + +int SoftBody::get_simulation_precision() { + return PhysicsServer::get_singleton()->soft_body_get_simulation_precision(physics_rid); +} + +void SoftBody::set_simulation_precision(int p_simulation_precision) { + PhysicsServer::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision); +} + +real_t SoftBody::get_total_mass() { + return PhysicsServer::get_singleton()->soft_body_get_total_mass(physics_rid); +} + +void SoftBody::set_total_mass(real_t p_total_mass) { + PhysicsServer::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass); +} + +void SoftBody::set_linear_stiffness(real_t p_linear_stiffness) { + PhysicsServer::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness); +} + +real_t SoftBody::get_linear_stiffness() { + return PhysicsServer::get_singleton()->soft_body_get_linear_stiffness(physics_rid); +} + +void SoftBody::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) { + PhysicsServer::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness); +} + +real_t SoftBody::get_areaAngular_stiffness() { + return PhysicsServer::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid); +} + +void SoftBody::set_volume_stiffness(real_t p_volume_stiffness) { + PhysicsServer::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness); +} + +real_t SoftBody::get_volume_stiffness() { + return PhysicsServer::get_singleton()->soft_body_get_volume_stiffness(physics_rid); +} + +real_t SoftBody::get_pressure_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_pressure_coefficient(physics_rid); +} + +void SoftBody::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient); +} + +real_t SoftBody::get_pose_matching_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid); +} + +void SoftBody::set_pressure_coefficient(real_t p_pressure_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient); +} + +real_t SoftBody::get_damping_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_damping_coefficient(physics_rid); +} + +void SoftBody::set_damping_coefficient(real_t p_damping_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient); +} + +real_t SoftBody::get_drag_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_drag_coefficient(physics_rid); +} + +void SoftBody::set_drag_coefficient(real_t p_drag_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient); +} + +Vector3 SoftBody::get_point_transform(int p_point_index) { + return PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index); +} + +void SoftBody::pin_point_toggle(int p_point_index) { + pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index))); +} + +void SoftBody::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) { + _pin_point_on_physics_server(p_point_index, pin); + if (pin) { + _add_pinned_point(p_point_index, p_spatial_attachment_path); + } else { + _remove_pinned_point(p_point_index); + } +} + +bool SoftBody::is_point_pinned(int p_point_index) const { + return -1 != _has_pinned_point(p_point_index); +} + +void SoftBody::set_ray_pickable(bool p_ray_pickable) { + + ray_pickable = p_ray_pickable; + _update_pickable(); +} + +bool SoftBody::is_ray_pickable() const { + + return ray_pickable; +} + +SoftBody::SoftBody() : + MeshInstance(), + physics_rid(PhysicsServer::get_singleton()->soft_body_create()), + mesh_owner(false), + collision_mask(1), + collision_layer(1), + simulation_started(false), + pinned_points_cache_dirty(true) { + + PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id()); + //set_notify_transform(true); + set_physics_process_internal(true); +} + +SoftBody::~SoftBody() { +} + +void SoftBody::reset_softbody_pin() { + PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid); + PoolVector<PinnedPoint>::Read pps = pinned_points.read(); + for (int i = pinned_points.size() - 1; 0 < i; --i) { + PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true); + } +} + +void SoftBody::_make_cache_dirty() { + pinned_points_cache_dirty = true; +} + +void SoftBody::_update_cache_pin_points_datas() { + if (!pinned_points_cache_dirty) + return; + + pinned_points_cache_dirty = false; + + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { + + if (!w[i].spatial_attachment_path.is_empty()) { + w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path)); + } + if (!w[i].spatial_attachment) { + ERR_PRINT("Spatial node not defined in the pinned point, Softbody undefined behaviour!"); + } + } +} + +void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) { + PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin); +} + +void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) { + SoftBody::PinnedPoint *pinned_point; + if (-1 == _get_pinned_point(p_point_index, pinned_point)) { + + // Create new + PinnedPoint pp; + pp.point_index = p_point_index; + pp.spatial_attachment_path = p_spatial_attachment_path; + + if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) { + pp.spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path)); + pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index)); + } + + pinned_points.push_back(pp); + + } else { + + pinned_point->point_index = p_point_index; + pinned_point->spatial_attachment_path = p_spatial_attachment_path; + + if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) { + pinned_point->spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path)); + pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index)); + } + } +} + +void SoftBody::_reset_points_offsets() { + + if (!Engine::get_singleton()->is_editor_hint()) + return; + + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { + + if (!r[i].spatial_attachment) + w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(r[i].spatial_attachment_path)); + + if (!r[i].spatial_attachment) + continue; + + w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index)); + } +} + +void SoftBody::_remove_pinned_point(int p_point_index) { + const int id(_has_pinned_point(p_point_index)); + if (-1 != id) { + pinned_points.remove(id); + } +} + +int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_point) const { + const int id = _has_pinned_point(p_point_index); + if (-1 == id) { + r_point = NULL; + return -1; + } else { + r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.read()[id]); + return id; + } +} + +int SoftBody::_has_pinned_point(int p_point_index) const { + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { + if (p_point_index == r[i].point_index) { + return i; + } + } + return -1; +} diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h new file mode 100644 index 0000000000..ee3d8d87cf --- /dev/null +++ b/scene/3d/soft_body.h @@ -0,0 +1,199 @@ +/*************************************************************************/ +/* soft_body.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SOFT_PHYSICS_BODY_H +#define SOFT_PHYSICS_BODY_H + +#include "scene/3d/mesh_instance.h" + +class SoftBody; + +class SoftBodyVisualServerHandler { + + friend class SoftBody; + + RID mesh; + int surface; + PoolVector<uint8_t> buffer; + uint32_t stride; + uint32_t offset_vertices; + uint32_t offset_normal; + + PoolVector<uint8_t>::Write write_buffer; + +private: + SoftBodyVisualServerHandler(); + bool is_ready() { return mesh.is_valid(); } + void prepare(RID p_mesh_rid, int p_surface); + void clear(); + void open(); + void close(); + void commit_changes(); + +public: + void set_vertex(int p_vertex_id, const void *p_vector3); + void set_normal(int p_vertex_id, const void *p_vector3); + void set_aabb(const AABB &p_aabb); +}; + +class SoftBody : public MeshInstance { + GDCLASS(SoftBody, MeshInstance); + +public: + struct PinnedPoint { + int point_index; + NodePath spatial_attachment_path; + Spatial *spatial_attachment; // Cache + Vector3 offset; + + PinnedPoint(); + PinnedPoint(const PinnedPoint &obj_tocopy); + }; + +private: + SoftBodyVisualServerHandler visual_server_handler; + + RID physics_rid; + + bool mesh_owner; + uint32_t collision_mask; + uint32_t collision_layer; + NodePath parent_collision_ignore; + PoolVector<PinnedPoint> pinned_points; + bool simulation_started; + bool pinned_points_cache_dirty; + + Ref<ArrayMesh> debug_mesh_cache; + class MeshInstance *debug_mesh; + + bool capture_input_on_drag; + bool ray_pickable; + + void _update_pickable(); + +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; + + bool _set_property_pinned_points_indices(const Array &p_indices); + bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value); + bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const; + + virtual void _changed_callback(Object *p_changed, const char *p_prop); + + void _notification(int p_what); + static void _bind_methods(); + + virtual String get_configuration_warning() const; + +protected: + void _draw_soft_mesh(); + +public: + void update_physics_server(); + void become_mesh_owner(); + + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + + void set_collision_layer_bit(int p_bit, bool p_value); + bool get_collision_layer_bit(int p_bit) const; + + void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore); + const NodePath &get_parent_collision_ignore() const; + + void set_pinned_points_indices(PoolVector<PinnedPoint> p_pinned_points_indices); + PoolVector<PinnedPoint> get_pinned_points_indices(); + + void set_simulation_precision(int p_simulation_precision); + int get_simulation_precision(); + + void set_total_mass(real_t p_total_mass); + real_t get_total_mass(); + + void set_linear_stiffness(real_t p_linear_stiffness); + real_t get_linear_stiffness(); + + void set_areaAngular_stiffness(real_t p_areaAngular_stiffness); + real_t get_areaAngular_stiffness(); + + void set_volume_stiffness(real_t p_volume_stiffness); + real_t get_volume_stiffness(); + + void set_pressure_coefficient(real_t p_pressure_coefficient); + real_t get_pressure_coefficient(); + + void set_pose_matching_coefficient(real_t p_pose_matching_coefficient); + real_t get_pose_matching_coefficient(); + + void set_damping_coefficient(real_t p_damping_coefficient); + real_t get_damping_coefficient(); + + void set_drag_coefficient(real_t p_drag_coefficient); + real_t get_drag_coefficient(); + + void add_collision_exception_with(Node *p_node); + void remove_collision_exception_with(Node *p_node); + + Vector3 get_point_transform(int p_point_index); + + void pin_point_toggle(int p_point_index); + void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath()); + bool is_point_pinned(int p_point_index) const; + + void set_ray_pickable(bool p_ray_pickable); + bool is_ray_pickable() const; + + SoftBody(); + ~SoftBody(); + +private: + void reset_softbody_pin(); + + void _make_cache_dirty(); + void _update_cache_pin_points_datas(); + + void _pin_point_on_physics_server(int p_point_index, bool pin); + void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path); + void _reset_points_offsets(); + + void _remove_pinned_point(int p_point_index); + int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const; + int _has_pinned_point(int p_point_index) const; +}; + +#endif // SOFT_PHYSICS_BODY_H diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 748aa8aad4..d52f634639 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -185,10 +185,8 @@ void Spatial::_notification(int p_what) { if (data.gizmo.is_valid()) { data.gizmo->create(); - if (data.gizmo->can_draw()) { - if (is_visible_in_tree()) { - data.gizmo->redraw(); - } + if (is_visible_in_tree()) { + data.gizmo->redraw(); } data.gizmo->transform(); } @@ -202,6 +200,7 @@ void Spatial::_notification(int p_what) { #ifdef TOOLS_ENABLED if (data.gizmo.is_valid()) { data.gizmo->free(); + data.gizmo.unref(); } #endif @@ -280,6 +279,10 @@ Transform Spatial::get_global_transform() const { data.global_transform = data.local_transform; } + if (data.disable_scale) { + data.global_transform.basis.orthonormalize(); + } + data.dirty &= ~DIRTY_GLOBAL; } @@ -418,10 +421,8 @@ void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) { if (data.gizmo.is_valid() && is_inside_world()) { data.gizmo->create(); - if (data.gizmo->can_draw()) { - if (is_visible_in_tree()) { - data.gizmo->redraw(); - } + if (is_visible_in_tree()) { + data.gizmo->redraw(); } data.gizmo->transform(); } @@ -447,12 +448,10 @@ void Spatial::_update_gizmo() { return; data.gizmo_dirty = false; if (data.gizmo.is_valid()) { - if (data.gizmo->can_draw()) { - if (is_visible_in_tree()) - data.gizmo->redraw(); - else - data.gizmo->clear(); - } + if (is_visible_in_tree()) + data.gizmo->redraw(); + else + data.gizmo->clear(); } #endif } @@ -467,6 +466,15 @@ void Spatial::set_disable_gizmo(bool p_enabled) { #endif +void Spatial::set_disable_scale(bool p_enabled) { + + data.disable_scale = p_enabled; +} + +bool Spatial::is_scale_disabled() const { + return data.disable_scale; +} + void Spatial::set_as_toplevel(bool p_enabled) { if (data.toplevel == p_enabled) @@ -632,19 +640,15 @@ void Spatial::scale_object_local(const Vector3 &p_scale) { void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) { - Basis rotation(p_axis, p_angle); Transform t = get_global_transform(); - t.basis = rotation * t.basis; + t.basis.rotate(p_axis, p_angle); set_global_transform(t); } void Spatial::global_scale(const Vector3 &p_scale) { - Basis s; - s.set_scale(p_scale); - Transform t = get_global_transform(); - t.basis = s * t.basis; + t.basis.scale(p_scale); set_global_transform(t); } @@ -735,6 +739,8 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification); ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel); ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel); + ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Spatial::set_disable_scale); + ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Spatial::is_scale_disabled); ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world); ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo); @@ -755,15 +761,6 @@ void Spatial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Spatial::set_notify_transform); ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Spatial::is_transform_notification_enabled); - void rotate(const Vector3 &p_axis, float p_angle); - void rotate_x(float p_angle); - void rotate_y(float p_angle); - void rotate_z(float p_angle); - void translate(const Vector3 &p_offset); - void scale(const Vector3 &p_ratio); - void global_rotate(const Vector3 &p_axis, float p_angle); - void global_translate(const Vector3 &p_offset); - ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Spatial::rotate); ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Spatial::global_rotate); ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Spatial::global_scale); @@ -791,12 +788,13 @@ void Spatial::_bind_methods() { //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ; ADD_GROUP("Transform", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); + ADD_GROUP("Matrix", ""); + ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); ADD_GROUP("Visibility", ""); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo"); @@ -817,6 +815,7 @@ Spatial::Spatial() : data.viewport = NULL; data.inside_world = false; data.visible = true; + data.disable_scale = false; #ifdef TOOLS_ENABLED data.gizmo_disabled = false; diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index a43bed3e4a..8d3c32d116 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -48,9 +48,9 @@ public: virtual void clear() = 0; virtual void redraw() = 0; virtual void free() = 0; - virtual bool can_draw() const = 0; SpatialGizmo(); + virtual ~SpatialGizmo() {} }; class Spatial : public Node { @@ -92,6 +92,7 @@ class Spatial : public Node { bool notify_transform; bool visible; + bool disable_scale; #ifdef TOOLS_ENABLED Ref<SpatialGizmo> gizmo; @@ -153,6 +154,9 @@ public: void set_as_toplevel(bool p_enabled); bool is_set_as_toplevel() const; + void set_disable_scale(bool p_enabled); + bool is_scale_disabled() const; + void set_disable_gizmo(bool p_enabled); void update_gizmo(); void set_gizmo(const Ref<SpatialGizmo> &p_gizmo); diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp index c547e76e30..d96b003a81 100644 --- a/scene/3d/spatial_velocity_tracker.cpp +++ b/scene/3d/spatial_velocity_tracker.cpp @@ -53,11 +53,11 @@ void SpatialVelocityTracker::update_position(const Vector3 &p_position) { if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest position_history_len = MIN(position_history.size(), position_history_len + 1); for (int i = position_history_len - 1; i > 0; i--) { - position_history[i] = position_history[i - 1]; + position_history.write[i] = position_history[i - 1]; } } - position_history[0] = ph; + position_history.write[0] = ph; } Vector3 SpatialVelocityTracker::get_tracked_linear_velocity() const { @@ -114,7 +114,7 @@ void SpatialVelocityTracker::reset(const Vector3 &p_new_pos) { ph.frame = Engine::get_singleton()->get_idle_frame_ticks(); } - position_history[0] = ph; + position_history.write[0] = ph; position_history_len = 1; } diff --git a/scene/3d/spring_arm.cpp b/scene/3d/spring_arm.cpp new file mode 100644 index 0000000000..492c6b806e --- /dev/null +++ b/scene/3d/spring_arm.cpp @@ -0,0 +1,172 @@ +/*************************************************************************/ +/* spring_arm.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "spring_arm.h" +#include "engine.h" +#include "scene/3d/collision_object.h" +#include "scene/resources/sphere_shape.h" +#include "servers/physics_server.h" + +SpringArm::SpringArm() : + spring_length(1), + mask(1), + current_spring_length(0), + margin(0.01) {} + +void SpringArm::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + if (!Engine::get_singleton()->is_editor_hint()) { + set_process_internal(true); + } + break; + case NOTIFICATION_EXIT_TREE: + if (!Engine::get_singleton()->is_editor_hint()) { + set_process_internal(false); + } + break; + case NOTIFICATION_INTERNAL_PROCESS: + process_spring(); + break; + } +} + +void SpringArm::_bind_methods() { + + ClassDB::bind_method(D_METHOD("get_hit_length"), &SpringArm::get_hit_length); + + ClassDB::bind_method(D_METHOD("set_length", "length"), &SpringArm::set_length); + ClassDB::bind_method(D_METHOD("get_length"), &SpringArm::get_length); + + ClassDB::bind_method(D_METHOD("set_shape", "shape"), &SpringArm::set_shape); + ClassDB::bind_method(D_METHOD("get_shape"), &SpringArm::get_shape); + + ClassDB::bind_method(D_METHOD("add_excluded_object", "RID"), &SpringArm::add_excluded_object); + ClassDB::bind_method(D_METHOD("remove_excluded_object", "RID"), &SpringArm::remove_excluded_object); + ClassDB::bind_method(D_METHOD("clear_excluded_objects"), &SpringArm::clear_excluded_objects); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SpringArm::set_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &SpringArm::get_mask); + + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &SpringArm::set_margin); + ClassDB::bind_method(D_METHOD("get_margin"), &SpringArm::get_margin); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), "set_shape", "get_shape"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "spring_length"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "margin"), "set_margin", "get_margin"); +} + +float SpringArm::get_length() const { + return spring_length; +} + +void SpringArm::set_length(float p_length) { + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) + update_gizmo(); + + spring_length = p_length; +} + +void SpringArm::set_shape(Ref<Shape> p_shape) { + shape = p_shape; +} + +Ref<Shape> SpringArm::get_shape() const { + return shape; +} + +void SpringArm::set_mask(uint32_t p_mask) { + mask = p_mask; +} + +uint32_t SpringArm::get_mask() { + return mask; +} + +float SpringArm::get_margin() { + return margin; +} + +void SpringArm::set_margin(float p_margin) { + margin = p_margin; +} + +void SpringArm::add_excluded_object(RID p_rid) { + excluded_objects.insert(p_rid); +} + +bool SpringArm::remove_excluded_object(RID p_rid) { + return excluded_objects.erase(p_rid); +} + +void SpringArm::clear_excluded_objects() { + excluded_objects.clear(); +} + +float SpringArm::get_hit_length() { + return current_spring_length; +} + +void SpringArm::process_spring() { + // From + real_t motion_delta(1); + real_t motion_delta_unsafe(1); + + Vector3 motion; + const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1))); + + if (shape.is_null()) { + motion = Vector3(cast_direction * (spring_length)); + PhysicsDirectSpaceState::RayResult r; + bool intersected = get_world()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask); + if (intersected) { + float dist = get_global_transform().origin.distance_to(r.position); + dist -= margin; + motion_delta = dist / (spring_length); + } + } else { + motion = Vector3(cast_direction * spring_length); + get_world()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask); + } + + current_spring_length = spring_length * motion_delta; + Transform childs_transform; + childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta); + + for (int i = get_child_count() - 1; 0 <= i; --i) { + + Spatial *child = Object::cast_to<Spatial>(get_child(i)); + if (child) { + childs_transform.basis = child->get_global_transform().basis; + child->set_global_transform(childs_transform); + } + } +} diff --git a/scene/3d/spring_arm.h b/scene/3d/spring_arm.h new file mode 100644 index 0000000000..24d912d371 --- /dev/null +++ b/scene/3d/spring_arm.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* spring_arm.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SPRING_ARM_H +#define SPRING_ARM_H + +#include "scene/3d/spatial.h" + +class SpringArm : public Spatial { + GDCLASS(SpringArm, Spatial); + + Ref<Shape> shape; + Set<RID> excluded_objects; + float spring_length; + bool keep_child_basis; + float current_spring_length; + uint32_t mask; + float margin; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_length(float p_length); + float get_length() const; + void set_shape(Ref<Shape> p_shape); + Ref<Shape> get_shape() const; + void set_mask(uint32_t p_mask); + uint32_t get_mask(); + void add_excluded_object(RID p_rid); + bool remove_excluded_object(RID p_rid); + void clear_excluded_objects(); + float get_hit_length(); + void set_margin(float p_margin); + float get_margin(); + + SpringArm(); + +private: + void process_spring(); +}; + +#endif diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index 385956dc16..f9d096633c 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -366,22 +366,14 @@ void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) { const Vector3 &right = wheel.m_raycastInfo.m_wheelAxleWS; Vector3 fwd = up.cross(right); fwd = fwd.normalized(); - //up = right.cross(fwd); - //up.normalize(); //rotate around steering over de wheelAxleWS real_t steering = wheel.steers ? m_steeringValue : 0.0; - //print_line(itos(p_idx)+": "+rtos(steering)); Basis steeringMat(up, steering); Basis rotatingMat(right, wheel.m_rotation); - /* - if (p_idx==1) - print_line("steeringMat " +steeringMat); - */ - Basis basis2( right[0], up[0], fwd[0], right[1], up[1], fwd[1], @@ -420,8 +412,6 @@ real_t VehicleBody::_ray_cast(int p_idx, PhysicsDirectBodyState *s) { wheel.m_raycastInfo.m_groundObject = 0; if (col) { - //print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target); - //print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col)); param = source.distance_to(rr.position) / source.distance_to(target); depth = raylen * param; wheel.m_raycastInfo.m_contactNormalWS = rr.normal; @@ -524,7 +514,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, real_t p_rollInfluence) { + PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) { real_t normalLenSqr = normal.length_squared(); //ERR_FAIL_COND( normalLenSqr < real_t(1.1)); @@ -677,8 +667,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { //collapse all those loops into one! for (int i = 0; i < wheels.size(); i++) { - m_sideImpulse[i] = real_t(0.); - m_forwardImpulse[i] = real_t(0.); + m_sideImpulse.write[i] = real_t(0.); + m_forwardImpulse.write[i] = real_t(0.); } { @@ -693,22 +683,22 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis; - m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X); + m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X); //m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS; const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS; real_t proj = m_axle[i].dot(surfNormalWS); - m_axle[i] -= surfNormalWS * proj; - m_axle[i] = m_axle[i].normalized(); + m_axle.write[i] -= surfNormalWS * proj; + m_axle.write[i] = m_axle[i].normalized(); - m_forwardWS[i] = surfNormalWS.cross(m_axle[i]); - m_forwardWS[i].normalize(); + m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]); + m_forwardWS.write[i].normalize(); _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], wheelInfo.m_rollInfluence); + m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence); - m_sideImpulse[i] *= sideFrictionStiffness2; + m_sideImpulse.write[i] *= sideFrictionStiffness2; } } } @@ -739,7 +729,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break) - m_forwardImpulse[wheel] = real_t(0.); + m_forwardImpulse.write[wheel] = real_t(0.); wheelInfo.m_skidInfo = real_t(1.); if (wheelInfo.m_raycastInfo.m_isInContact) { @@ -750,7 +740,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { real_t maximpSquared = maximp * maximpSide; - m_forwardImpulse[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep; + m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep; real_t x = (m_forwardImpulse[wheel]) * fwdFactor; real_t y = (m_sideImpulse[wheel]) * sideFactor; @@ -772,8 +762,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { for (int wheel = 0; wheel < wheels.size(); wheel++) { if (m_sideImpulse[wheel] != real_t(0.)) { if (wheels[wheel]->m_skidInfo < real_t(1.)) { - m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo; - m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo; + m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo; + m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo; } } } @@ -942,8 +932,6 @@ VehicleBody::VehicleBody() : engine_force = 0; brake = 0; - friction = 1; - state = NULL; ccd = false; diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 1ac3693cc4..68fbf8d873 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, real_t p_rollInfluence); + void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence); real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint); void _update_friction(PhysicsDirectBodyState *s); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 00541a7d8a..767518dc83 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -105,12 +105,28 @@ uint32_t VisualInstance::get_layer_mask() const { return layers; } +void VisualInstance::set_layer_mask_bit(int p_layer, bool p_enable) { + ERR_FAIL_INDEX(p_layer, 32); + if (p_enable) { + set_layer_mask(layers | (1 << p_layer)); + } else { + set_layer_mask(layers & (~(1 << p_layer))); + } +} + +bool VisualInstance::get_layer_mask_bit(int p_layer) const { + ERR_FAIL_INDEX_V(p_layer, 32, false); + return (layers & (1 << p_layer)); +} + void VisualInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("_get_visual_instance_rid"), &VisualInstance::_get_visual_instance_rid); ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance::set_base); ClassDB::bind_method(D_METHOD("set_layer_mask", "mask"), &VisualInstance::set_layer_mask); ClassDB::bind_method(D_METHOD("get_layer_mask"), &VisualInstance::get_layer_mask); + ClassDB::bind_method(D_METHOD("set_layer_mask_bit", "layer", "enabled"), &VisualInstance::set_layer_mask_bit); + ClassDB::bind_method(D_METHOD("get_layer_mask_bit", "layer"), &VisualInstance::get_layer_mask_bit); ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance::get_transformed_aabb); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index 8458a343b2..9249bc04ce 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -73,6 +73,9 @@ public: void set_layer_mask(uint32_t p_mask); uint32_t get_layer_mask() const; + void set_layer_mask_bit(int p_layer, bool p_enable); + bool get_layer_mask_bit(int p_layer) const; + VisualInstance(); ~VisualInstance(); }; diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 670df5cc7f..e846e1763d 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -113,7 +113,7 @@ static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) { rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \ if (min > rad || max < -rad) return false; - /*======================== Z-tests ========================*/ +/*======================== Z-tests ========================*/ #define AXISTEST_Z12(a, b, fa, fb) \ p1 = a * v1.x - b * v1.y; \ @@ -409,16 +409,16 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p } //put this temporarily here, corrected in a later step - bake_cells[p_idx].albedo[0] += albedo_accum.r; - bake_cells[p_idx].albedo[1] += albedo_accum.g; - bake_cells[p_idx].albedo[2] += albedo_accum.b; - bake_cells[p_idx].emission[0] += emission_accum.r; - bake_cells[p_idx].emission[1] += emission_accum.g; - bake_cells[p_idx].emission[2] += emission_accum.b; - bake_cells[p_idx].normal[0] += normal_accum.x; - bake_cells[p_idx].normal[1] += normal_accum.y; - bake_cells[p_idx].normal[2] += normal_accum.z; - bake_cells[p_idx].alpha += alpha; + bake_cells.write[p_idx].albedo[0] += albedo_accum.r; + bake_cells.write[p_idx].albedo[1] += albedo_accum.g; + bake_cells.write[p_idx].albedo[2] += albedo_accum.b; + bake_cells.write[p_idx].emission[0] += emission_accum.r; + bake_cells.write[p_idx].emission[1] += emission_accum.g; + bake_cells.write[p_idx].emission[2] += emission_accum.b; + bake_cells.write[p_idx].normal[0] += normal_accum.x; + bake_cells.write[p_idx].normal[1] += normal_accum.y; + bake_cells.write[p_idx].normal[2] += normal_accum.z; + bake_cells.write[p_idx].alpha += alpha; } else { //go down @@ -465,9 +465,9 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p //sub cell must be created uint32_t child_idx = bake_cells.size(); - bake_cells[p_idx].children[i] = child_idx; + bake_cells.write[p_idx].children[i] = child_idx; bake_cells.resize(bake_cells.size() + 1); - bake_cells[child_idx].level = p_level + 1; + bake_cells.write[child_idx].level = p_level + 1; } _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); @@ -483,7 +483,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color ret.resize(bake_texture_size * bake_texture_size); for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { - ret[i] = p_color_add; + ret.write[i] = p_color_add; } return ret; @@ -491,8 +491,6 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color p_image = p_image->duplicate(); if (p_image->is_compressed()) { - print_line("DECOMPRESSING!!!!"); - p_image->decompress(); } p_image->convert(Image::FORMAT_RGBA8); @@ -509,7 +507,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color c.a = r[i * 4 + 3] / 255.0; - ret[i] = c; + ret.write[i] = c; } return ret; @@ -686,13 +684,13 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) { - bake_light[p_idx].x = p_x; - bake_light[p_idx].y = p_y; - bake_light[p_idx].z = p_z; + bake_light.write[p_idx].x = p_x; + bake_light.write[p_idx].y = p_y; + bake_light.write[p_idx].z = p_z; if (p_level == cell_subdiv - 1) { - bake_light[p_idx].next_leaf = first_leaf; + bake_light.write[p_idx].next_leaf = first_leaf; first_leaf = p_idx; } else { @@ -859,7 +857,6 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C int idx = first_leaf; while (idx >= 0) { - //print_line("plot idx " + itos(idx)); Light *light = &light_data[idx]; Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); @@ -949,7 +946,6 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color int idx = first_leaf; while (idx >= 0) { - //print_line("plot idx " + itos(idx)); Light *light = &light_data[idx]; Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); @@ -1079,7 +1075,6 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi int idx = first_leaf; while (idx >= 0) { - //print_line("plot idx " + itos(idx)); Light *light = &light_data[idx]; Vector3 to(light->x + 0.5, light->y + 0.5, light->z + 0.5); @@ -1197,33 +1192,33 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { leaf_voxel_count++; float alpha = bake_cells[p_idx].alpha; - bake_cells[p_idx].albedo[0] /= alpha; - bake_cells[p_idx].albedo[1] /= alpha; - bake_cells[p_idx].albedo[2] /= alpha; + bake_cells.write[p_idx].albedo[0] /= alpha; + bake_cells.write[p_idx].albedo[1] /= alpha; + bake_cells.write[p_idx].albedo[2] /= alpha; //transfer emission to light - bake_cells[p_idx].emission[0] /= alpha; - bake_cells[p_idx].emission[1] /= alpha; - bake_cells[p_idx].emission[2] /= alpha; + bake_cells.write[p_idx].emission[0] /= alpha; + bake_cells.write[p_idx].emission[1] /= alpha; + bake_cells.write[p_idx].emission[2] /= alpha; - bake_cells[p_idx].normal[0] /= alpha; - bake_cells[p_idx].normal[1] /= alpha; - bake_cells[p_idx].normal[2] /= alpha; + bake_cells.write[p_idx].normal[0] /= alpha; + bake_cells.write[p_idx].normal[1] /= alpha; + bake_cells.write[p_idx].normal[2] /= alpha; Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]); if (n.length() < 0.01) { //too much fight over normal, zero it - bake_cells[p_idx].normal[0] = 0; - bake_cells[p_idx].normal[1] = 0; - bake_cells[p_idx].normal[2] = 0; + bake_cells.write[p_idx].normal[0] = 0; + bake_cells.write[p_idx].normal[1] = 0; + bake_cells.write[p_idx].normal[2] = 0; } else { n.normalize(); - bake_cells[p_idx].normal[0] = n.x; - bake_cells[p_idx].normal[1] = n.y; - bake_cells[p_idx].normal[2] = n.z; + bake_cells.write[p_idx].normal[0] = n.x; + bake_cells.write[p_idx].normal[1] = n.y; + bake_cells.write[p_idx].normal[2] = n.z; } - bake_cells[p_idx].alpha = 1.0; + bake_cells.write[p_idx].alpha = 1.0; /*if (bake_light.size()) { for(int i=0;i<6;i++) { @@ -1235,20 +1230,20 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { //go down - bake_cells[p_idx].emission[0] = 0; - bake_cells[p_idx].emission[1] = 0; - bake_cells[p_idx].emission[2] = 0; - bake_cells[p_idx].normal[0] = 0; - bake_cells[p_idx].normal[1] = 0; - bake_cells[p_idx].normal[2] = 0; - bake_cells[p_idx].albedo[0] = 0; - bake_cells[p_idx].albedo[1] = 0; - bake_cells[p_idx].albedo[2] = 0; + bake_cells.write[p_idx].emission[0] = 0; + bake_cells.write[p_idx].emission[1] = 0; + bake_cells.write[p_idx].emission[2] = 0; + bake_cells.write[p_idx].normal[0] = 0; + bake_cells.write[p_idx].normal[1] = 0; + bake_cells.write[p_idx].normal[2] = 0; + bake_cells.write[p_idx].albedo[0] = 0; + bake_cells.write[p_idx].albedo[1] = 0; + bake_cells.write[p_idx].albedo[2] = 0; if (bake_light.size()) { for (int j = 0; j < 6; j++) { - bake_light[p_idx].accum[j][0] = 0; - bake_light[p_idx].accum[j][1] = 0; - bake_light[p_idx].accum[j][2] = 0; + bake_light.write[p_idx].accum[j][0] = 0; + bake_light.write[p_idx].accum[j][1] = 0; + bake_light.write[p_idx].accum[j][2] = 0; } } @@ -1267,29 +1262,29 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { if (bake_light.size() > 0) { for (int j = 0; j < 6; j++) { - bake_light[p_idx].accum[j][0] += bake_light[child].accum[j][0]; - bake_light[p_idx].accum[j][1] += bake_light[child].accum[j][1]; - bake_light[p_idx].accum[j][2] += bake_light[child].accum[j][2]; + bake_light.write[p_idx].accum[j][0] += bake_light[child].accum[j][0]; + bake_light.write[p_idx].accum[j][1] += bake_light[child].accum[j][1]; + bake_light.write[p_idx].accum[j][2] += bake_light[child].accum[j][2]; } - bake_cells[p_idx].emission[0] += bake_cells[child].emission[0]; - bake_cells[p_idx].emission[1] += bake_cells[child].emission[1]; - bake_cells[p_idx].emission[2] += bake_cells[child].emission[2]; + bake_cells.write[p_idx].emission[0] += bake_cells[child].emission[0]; + bake_cells.write[p_idx].emission[1] += bake_cells[child].emission[1]; + bake_cells.write[p_idx].emission[2] += bake_cells[child].emission[2]; } children_found++; } - bake_cells[p_idx].alpha = alpha_average / 8.0; + bake_cells.write[p_idx].alpha = alpha_average / 8.0; if (bake_light.size() && children_found) { float divisor = Math::lerp(8, children_found, propagation); for (int j = 0; j < 6; j++) { - bake_light[p_idx].accum[j][0] /= divisor; - bake_light[p_idx].accum[j][1] /= divisor; - bake_light[p_idx].accum[j][2] /= divisor; + bake_light.write[p_idx].accum[j][0] /= divisor; + bake_light.write[p_idx].accum[j][1] /= divisor; + bake_light.write[p_idx].accum[j][2] /= divisor; } - bake_cells[p_idx].emission[0] /= divisor; - bake_cells[p_idx].emission[1] /= divisor; - bake_cells[p_idx].emission[2] /= divisor; + bake_cells.write[p_idx].emission[0] /= divisor; + bake_cells.write[p_idx].emission[1] /= divisor; + bake_cells.write[p_idx].emission[2] /= divisor; } } } @@ -1498,12 +1493,8 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector for (int i = 0; i < 6; i++) { //anisotropic read light float amount = p_direction.dot(aniso_normal[i]); - //if (c == 0) { - // print_line("\t" + itos(n) + " aniso " + itos(i) + " " + rtos(light[cell].accum[i][0]) + " VEC: " + aniso_normal[i]); - //} if (amount < 0) amount = 0; - //amount = 1; color[c][n].x += light[cell].accum[i][0] * amount; color[c][n].y += light[cell].accum[i][1] * amount; color[c][n].z += light[cell].accum[i][2] * amount; @@ -1513,8 +1504,6 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector color[c][n].y += cells[cell].emission[1]; color[c][n].z += cells[cell].emission[2]; } - - //print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]); } } @@ -1559,8 +1548,6 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter); r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter); - - // print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha)); } Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture) { @@ -1577,8 +1564,6 @@ Vector3 VoxelLightBaker::_voxel_cone_trace(const Vector3 &p_pos, const Vector3 & while (dist < max_distance && alpha < 0.95) { float diameter = MAX(1.0, 2.0 * p_aperture * dist); - //print_line("VCT: pos " + (p_pos + dist * p_normal) + " dist " + rtos(dist) + " mipmap " + rtos(log2(diameter)) + " alpha " + rtos(alpha)); - //Plane scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) ); _sample_baked_octree_filtered_and_anisotropic(p_pos + dist * p_normal, p_normal, log2(diameter), scolor, salpha); float a = (1.0 - alpha); color += scolor * a; @@ -1601,7 +1586,6 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 bitangent = tangent.cross(p_normal).normalized(); Basis normal_xform = Basis(tangent, bitangent, p_normal).transposed(); - // print_line("normal xform: " + normal_xform); const Vector3 *cone_dirs; const float *cone_weights; int cone_dir_count; @@ -1667,10 +1651,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 accum; for (int i = 0; i < cone_dir_count; i++) { - // if (i > 0) - // continue; Vector3 dir = normal_xform.xform(cone_dirs[i]).normalized(); //normal may not completely correct when transformed to cell - //print_line("direction: " + dir); accum += _voxel_cone_trace(p_pos, dir, cone_aperture) * cone_weights[i]; } @@ -1802,7 +1783,6 @@ void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) { LightMap *pixel = &p_line[p_x]; if (pixel->pos == Vector3()) return; - //print_line("pos: " + pixel->pos + " normal " + pixel->normal); switch (bake_mode) { case BAKE_MODE_CONE_TRACE: { pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; @@ -1810,8 +1790,6 @@ void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) { case BAKE_MODE_RAY_TRACE: { pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; } break; - // pixel->light = Vector3(1, 1, 1); - //} } } @@ -1895,7 +1873,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh if (bake_mode == BAKE_MODE_RAY_TRACE) { //blur - print_line("bluring, use pos for separatable copy"); //gauss kernel, 7 step sigma 2 static const float gauss_kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 }; //horizontal pass @@ -1960,8 +1937,6 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh #pragma omp parallel #endif for (int i = 0; i < height; i++) { - - //print_line("bake line " + itos(i) + " / " + itos(height)); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 1) #endif @@ -2304,7 +2279,6 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) { mm->set_transform_format(MultiMesh::TRANSFORM_3D); mm->set_color_format(MultiMesh::COLOR_8BIT); - print_line("leaf voxels: " + itos(leaf_voxel_count)); mm->set_instance_count(leaf_voxel_count); Ref<ArrayMesh> mesh; @@ -2403,25 +2377,25 @@ PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) { new_size++; demap.push_back(i); } - remap[i] = c; + remap.write[i] = c; } Vector<VoxelLightBakerOctree> octree; octree.resize(new_size); for (int i = 0; i < new_size; i++) { - octree[i].alpha = bake_cells[demap[i]].alpha; + octree.write[i].alpha = bake_cells[demap[i]].alpha; for (int j = 0; j < 6; j++) { for (int k = 0; k < 3; k++) { float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light l += bake_cells[demap[i]].emission[k]; //add emission - octree[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree + octree.write[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree } } for (int j = 0; j < 8; j++) { uint32_t child = bake_cells[demap[i]].children[j]; - octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; + octree.write[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; } } |