diff options
Diffstat (limited to 'servers')
40 files changed, 722 insertions, 223 deletions
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 84a87de2e2..d9b3579812 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -79,53 +79,27 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i p_dest[i] = AudioFrame(v0, v1); } - // For now, channels higher than stereo are almost ignored + // This will probably never be used, but added anyway if (C == 4) { - // FIXME: v2 and v3 are not being used (thus were commented out to prevent - // compilation warnings, but they should likely be uncommented *and* used). - // See also C == 6 with similar issues. float v0 = rb[(pos << 2) + 0]; float v1 = rb[(pos << 2) + 1]; - /* - float v2 = rb[(pos << 2) + 2]; - float v3 = rb[(pos << 2) + 3]; - */ float v0n = rb[(pos_next << 2) + 0]; float v1n = rb[(pos_next << 2) + 1]; - /* - float v2n = rb[(pos_next << 2) + 2]; - float v3n = rb[(pos_next << 2) + 3]; - */ - v0 += (v0n - v0) * frac; v1 += (v1n - v1) * frac; - /* - v2 += (v2n - v2) * frac; - v3 += (v3n - v3) * frac; - */ p_dest[i] = AudioFrame(v0, v1); } if (C == 6) { - // FIXME: Lot of unused assignments here, but it seems like intermediate calculations - // should be done as for C == 2 (C == 4 also has some unused assignments). float v0 = rb[(pos * 6) + 0]; float v1 = rb[(pos * 6) + 1]; - /* - float v2 = rb[(pos * 6) + 2]; - float v3 = rb[(pos * 6) + 3]; - float v4 = rb[(pos * 6) + 4]; - float v5 = rb[(pos * 6) + 5]; float v0n = rb[(pos_next * 6) + 0]; float v1n = rb[(pos_next * 6) + 1]; - float v2n = rb[(pos_next * 6) + 2]; - float v3n = rb[(pos_next * 6) + 3]; - float v4n = rb[(pos_next * 6) + 4]; - float v5n = rb[(pos_next * 6) + 5]; - */ + v0 += (v0n - v0) * frac; + v1 += (v1n - v1) * frac; p_dest[i] = AudioFrame(v0, v1); } } diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 7de0695e8c..02a0bed964 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -136,16 +136,20 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer(); unsigned int input_size = AudioDriver::get_singleton()->get_input_size(); + int mix_rate = AudioDriver::get_singleton()->get_mix_rate(); + int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1); +#ifdef DEBUG_ENABLED + unsigned int input_position = AudioDriver::get_singleton()->get_input_position(); +#endif - // p_frames is multiplied by two since an AudioFrame is stereo - if ((p_frames + MICROPHONE_PLAYBACK_DELAY * 2) > input_size) { + if (playback_delay > input_size) { for (int i = 0; i < p_frames; i++) { p_buffer[i] = AudioFrame(0.0f, 0.0f); } input_ofs = 0; } else { for (int i = 0; i < p_frames; i++) { - if (input_size >= input_ofs) { + if (input_size > input_ofs) { float l = (buf[input_ofs++] >> 16) / 32768.f; if (input_ofs >= buf.size()) { input_ofs = 0; @@ -162,6 +166,12 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr } } +#ifdef DEBUG_ENABLED + if (input_ofs > input_position && (input_ofs - input_position) < (p_frames * 2)) { + print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size)); + } +#endif + AudioDriver::get_singleton()->unlock(); } diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 2740f86d55..f6ed45cc9c 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -122,8 +122,6 @@ class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled { GDCLASS(AudioStreamPlaybackMicrophone, AudioStreamPlayback) friend class AudioStreamMicrophone; - static const int MICROPHONE_PLAYBACK_DELAY = 256; - bool active; unsigned int input_ofs; diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h index 11978882bc..e8f12e5efa 100644 --- a/servers/audio/effects/audio_effect_filter.h +++ b/servers/audio/effects/audio_effect_filter.h @@ -96,6 +96,11 @@ VARIANT_ENUM_CAST(AudioEffectFilter::FilterDB) class AudioEffectLowPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectLowPassFilter, AudioEffectFilter) + + void _validate_property(PropertyInfo &property) const { + if (property.name == "gain") property.usage = 0; + } + public: AudioEffectLowPassFilter() : AudioEffectFilter(AudioFilterSW::LOWPASS) {} @@ -103,6 +108,10 @@ public: class AudioEffectHighPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectHighPassFilter, AudioEffectFilter) + void _validate_property(PropertyInfo &property) const { + if (property.name == "gain") property.usage = 0; + } + public: AudioEffectHighPassFilter() : AudioEffectFilter(AudioFilterSW::HIGHPASS) {} @@ -110,6 +119,10 @@ public: class AudioEffectBandPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectBandPassFilter, AudioEffectFilter) + void _validate_property(PropertyInfo &property) const { + if (property.name == "gain") property.usage = 0; + } + public: AudioEffectBandPassFilter() : AudioEffectFilter(AudioFilterSW::BANDPASS) {} diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp index ef23e4aaf3..b032c91da2 100644 --- a/servers/audio/effects/reverb.cpp +++ b/servers/audio/effects/reverb.cpp @@ -36,22 +36,22 @@ const float Reverb::comb_tunings[MAX_COMBS] = { //freeverb comb tunings - 0.025306122448979593, - 0.026938775510204082, - 0.028956916099773241, - 0.03074829931972789, - 0.032244897959183672, - 0.03380952380952381, - 0.035306122448979592, - 0.036666666666666667 + 0.025306122448979593f, + 0.026938775510204082f, + 0.028956916099773241f, + 0.03074829931972789f, + 0.032244897959183672f, + 0.03380952380952381f, + 0.035306122448979592f, + 0.036666666666666667f }; const float Reverb::allpass_tunings[MAX_ALLPASS] = { //freeverb allpass tunings - 0.0051020408163265302, - 0.007732426303854875, - 0.01, - 0.012607709750566893 + 0.0051020408163265302f, + 0.007732426303854875f, + 0.01f, + 0.012607709750566893f }; void Reverb::process(float *p_src, float *p_dst, int p_frames) { diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index d36057b465..6fd996c3d3 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -80,6 +80,14 @@ double AudioDriver::get_mix_time() const { return total; } +void AudioDriver::input_buffer_init(int driver_buffer_frames) { + + const int input_buffer_channels = 2; + input_buffer.resize(driver_buffer_frames * input_buffer_channels * 4); + input_position = 0; + input_size = 0; +} + void AudioDriver::input_buffer_write(int32_t sample) { input_buffer.write[input_position++] = sample; @@ -452,6 +460,14 @@ void AudioServer::_mix_step() { to_mix = buffer_size; } +bool AudioServer::thread_has_channel_mix_buffer(int p_bus, int p_buffer) const { + if (p_bus < 0 || p_bus >= buses.size()) + return false; + if (p_buffer < 0 || p_buffer >= buses[p_bus]->channels.size()) + return false; + return true; +} + AudioFrame *AudioServer::thread_get_channel_mix_buffer(int p_bus, int p_buffer) { ERR_FAIL_INDEX_V(p_bus, buses.size(), NULL); @@ -926,6 +942,7 @@ void AudioServer::init() { channel_disable_threshold_db = GLOBAL_DEF_RST("audio/channel_disable_threshold_db", -60.0); channel_disable_frames = float(GLOBAL_DEF_RST("audio/channel_disable_time", 2.0)) * get_mix_rate(); + ProjectSettings::get_singleton()->set_custom_property_info("audio/channel_disable_time", PropertyInfo(Variant::REAL, "audio/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); buffer_size = 1024; //hardcoded for now init_channels_and_buffers(); @@ -1008,7 +1025,7 @@ void AudioServer::update() { void AudioServer::load_default_bus_layout() { - if (FileAccess::exists("res://default_bus_layout.tres")) { + if (ResourceLoader::exists("res://default_bus_layout.tres")) { Ref<AudioBusLayout> default_layout = ResourceLoader::load("res://default_bus_layout.tres"); if (default_layout.is_valid()) { set_bus_layout(default_layout); diff --git a/servers/audio_server.h b/servers/audio_server.h index ba6569eb38..52fa84e3e6 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -59,6 +59,7 @@ protected: void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true); void update_mix_time(int p_frames); + void input_buffer_init(int driver_buffer_frames); void input_buffer_write(int32_t sample); #ifdef DEBUG_ENABLED @@ -281,6 +282,7 @@ public: } //do not use from outside audio thread + bool thread_has_channel_mix_buffer(int p_bus, int p_buffer) const; AudioFrame *thread_get_channel_mix_buffer(int p_bus, int p_buffer); int thread_get_mix_buffer_size() const; int thread_find_bus_index(const StringName &p_name); diff --git a/servers/physics/area_pair_sw.cpp b/servers/physics/area_pair_sw.cpp index d2fef0ab77..5e295edcd1 100644 --- a/servers/physics/area_pair_sw.cpp +++ b/servers/physics/area_pair_sw.cpp @@ -147,10 +147,10 @@ Area2PairSW::~Area2PairSW() { if (colliding) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) + if (area_b->has_area_monitor_callback()) area_b->remove_area_from_query(area_a, shape_a, shape_b); - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) + if (area_a->has_area_monitor_callback()) area_a->remove_area_from_query(area_b, shape_b, shape_a); } diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp index 087ae570fb..f17f6f7014 100644 --- a/servers/physics/collision_solver_sat.cpp +++ b/servers/physics/collision_solver_sat.cpp @@ -98,7 +98,6 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_ Vector3 c = rel_A.cross(rel_B).cross(rel_B); - //if ( Math::abs(rel_A.dot(c) )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) { if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) { // should handle somehow.. diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp index 60505c08c5..3a965ff800 100644 --- a/servers/physics/joints/generic_6dof_joint_sw.cpp +++ b/servers/physics/joints/generic_6dof_joint_sw.cpp @@ -503,6 +503,24 @@ void Generic6DOFJointSW::set_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJoi case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: { // Not implemented in GodotPhysics backend } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: { + // Not implemented in GodotPhysics backend + } break; case PhysicsServer::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning } } @@ -585,6 +603,24 @@ real_t Generic6DOFJointSW::get_param(Vector3::Axis p_axis, PhysicsServer::G6DOFJ case PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT: { // Not implemented in GodotPhysics backend } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_STIFFNESS: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_DAMPING: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_DAMPING: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT: { + // Not implemented in GodotPhysics backend + } break; case PhysicsServer::G6DOF_JOINT_MAX: break; // Can't happen, but silences warning } return 0; @@ -610,6 +646,12 @@ void Generic6DOFJointSW::set_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJoin case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: { // Not implemented in GodotPhysics backend } break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: { + // Not implemented in GodotPhysics backend + } break; case PhysicsServer::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } } @@ -632,6 +674,12 @@ bool Generic6DOFJointSW::get_flag(Vector3::Axis p_axis, PhysicsServer::G6DOFJoin case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR: { // Not implemented in GodotPhysics backend } break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING: { + // Not implemented in GodotPhysics backend + } break; + case PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING: { + // Not implemented in GodotPhysics backend + } break; case PhysicsServer::G6DOF_JOINT_FLAG_MAX: break; // Can't happen, but silences warning } diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 76a6138817..fddb531a4f 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -40,6 +40,12 @@ #include "joints/pin_joint_sw.h" #include "joints/slider_joint_sw.h" +#define FLUSH_QUERY_CHECK \ + if (flushing_queries) { \ + ERR_EXPLAIN("Can't change this state while flushing queries. Use call_deferred()/set_deferred() to change monitoring state instead"); \ + ERR_FAIL(); \ + } + RID PhysicsServerSW::shape_create(ShapeType p_shape) { ShapeSW *shape = NULL; @@ -352,6 +358,8 @@ void PhysicsServerSW::area_clear_shapes(RID p_area) { void PhysicsServerSW::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { + FLUSH_QUERY_CHECK + AreaSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count()); @@ -435,6 +443,8 @@ void PhysicsServerSW::area_set_collision_mask(RID p_area, uint32_t p_mask) { void PhysicsServerSW::area_set_monitorable(RID p_area, bool p_monitorable) { + FLUSH_QUERY_CHECK + AreaSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); @@ -582,6 +592,8 @@ RID PhysicsServerSW::body_get_shape(RID p_body, int p_shape_idx) const { void PhysicsServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { + FLUSH_QUERY_CHECK + BodySW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); @@ -1459,6 +1471,8 @@ void PhysicsServerSW::flush_queries() { doing_sync = true; + flushing_queries = true; + uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); for (Set<const SpaceSW *>::Element *E = active_spaces.front(); E; E = E->next()) { @@ -1467,6 +1481,8 @@ void PhysicsServerSW::flush_queries() { space->call_queries(); } + flushing_queries = false; + if (ScriptDebugger::get_singleton() && ScriptDebugger::get_singleton()->is_profiling()) { uint64_t total_time[SpaceSW::ELAPSED_TIME_MAX]; @@ -1580,6 +1596,7 @@ PhysicsServerSW::PhysicsServerSW() { collision_pairs = 0; active = true; + flushing_queries = false; }; PhysicsServerSW::~PhysicsServerSW(){ diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 4131c5e248..b3c61403aa 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -51,6 +51,8 @@ class PhysicsServerSW : public PhysicsServer { int active_objects; int collision_pairs; + bool flushing_queries; + StepSW *stepper; Set<const SpaceSW *> active_spaces; @@ -365,6 +367,8 @@ public: virtual void flush_queries(); virtual void finish(); + virtual bool is_flushing_queries() const { return flushing_queries; } + int get_process_info(ProcessInfo p_info); PhysicsServerSW(); diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index 731749b8ce..3b5344f020 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -544,14 +544,24 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo AABB body_aabb; + bool shapes_found = false; + for (int i = 0; i < p_body->get_shape_count(); i++) { - if (i == 0) + if (p_body->is_shape_set_as_disabled(i)) + continue; + + if (!shapes_found) { body_aabb = p_body->get_shape_aabb(i); - else + shapes_found = true; + } else { body_aabb = body_aabb.merge(p_body->get_shape_aabb(i)); + } } + if (!shapes_found) { + return 0; + } // Undo the currently transform the physics server is aware of and apply the provided one body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb)); body_aabb = body_aabb.grow(p_margin); @@ -691,13 +701,23 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve r_result->collider_shape = 0; } AABB body_aabb; + bool shapes_found = false; for (int i = 0; i < p_body->get_shape_count(); i++) { - if (i == 0) + if (p_body->is_shape_set_as_disabled(i)) + continue; + + if (!shapes_found) { body_aabb = p_body->get_shape_aabb(i); - else + shapes_found = true; + } else { body_aabb = body_aabb.merge(p_body->get_shape_aabb(i)); + } + } + + if (!shapes_found) { + return false; } // Undo the currently transform the physics server is aware of and apply the provided one @@ -1183,6 +1203,7 @@ SpaceSW::SpaceSW() { body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1); body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI)); body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5); + ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::REAL, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); body_angular_velocity_damp_ratio = 10; broadphase = BroadPhaseSW::create_func(); diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index 9d515d2183..cdd35cf657 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -147,10 +147,10 @@ Area2Pair2DSW::~Area2Pair2DSW() { if (colliding) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) + if (area_b->has_area_monitor_callback()) area_b->remove_area_from_query(area_a, shape_a, shape_b); - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) + if (area_a->has_area_monitor_callback()) area_a->remove_area_from_query(area_b, shape_b, shape_a); } diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index aa063d6c1e..52362386d2 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -511,8 +511,7 @@ void Body2DSW::integrate_forces(real_t p_step) { if (continuous_cd_mode != Physics2DServer::CCD_MODE_DISABLED) { - motion = new_transform.get_origin() - get_transform().get_origin(); - //linear_velocity*p_step; + motion = linear_velocity * p_step; do_motion = true; } } diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp index 950f0f9d24..95195c8fff 100644 --- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp +++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp @@ -635,11 +635,15 @@ BroadPhase2DSW *BroadPhase2DHashGrid::_create() { BroadPhase2DHashGrid::BroadPhase2DHashGrid() { hash_table_size = GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096); + ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bp_hash_table_size", PropertyInfo(Variant::INT, "physics/2d/bp_hash_table_size", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); hash_table_size = Math::larger_prime(hash_table_size); hash_table = memnew_arr(PosBin *, hash_table_size); cell_size = GLOBAL_DEF("physics/2d/cell_size", 128); + ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/cell_size", PropertyInfo(Variant::INT, "physics/2d/cell_size", PROPERTY_HINT_RANGE, "0,512,1,or_greater")); + large_object_min_surface = GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512); + ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/large_object_surface_threshold_in_cells", PropertyInfo(Variant::INT, "physics/2d/large_object_surface_threshold_in_cells", PROPERTY_HINT_RANGE, "0,1024,1,or_greater")); for (uint32_t i = 0; i < hash_table_size; i++) hash_table[i] = NULL; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 4dd5b2040f..2f5b484040 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -244,6 +244,7 @@ CollisionObject2DSW::CollisionObject2DSW(Type p_type) { type = p_type; space = NULL; instance_id = 0; + canvas_instance_id = 0; collision_mask = 1; collision_layer = 1; pickable = true; diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index f2b2363499..f256910f52 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -49,6 +49,7 @@ private: Type type; RID self; ObjectID instance_id; + ObjectID canvas_instance_id; bool pickable; struct Shape { @@ -102,6 +103,9 @@ public: _FORCE_INLINE_ void set_instance_id(const ObjectID &p_instance_id) { instance_id = p_instance_id; } _FORCE_INLINE_ ObjectID get_instance_id() const { return instance_id; } + _FORCE_INLINE_ void set_canvas_instance_id(const ObjectID &p_canvas_instance_id) { canvas_instance_id = p_canvas_instance_id; } + _FORCE_INLINE_ ObjectID get_canvas_instance_id() const { return canvas_instance_id; } + void _shape_changed(); _FORCE_INLINE_ Type get_type() const { return type; } diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 000e38c4a2..45310ec4b3 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -36,6 +36,12 @@ #include "core/project_settings.h" #include "core/script_language.h" +#define FLUSH_QUERY_CHECK \ + if (flushing_queries) { \ + ERR_EXPLAIN("Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead"); \ + ERR_FAIL(); \ + } + RID Physics2DServerSW::_shape_create(ShapeType p_shape) { Shape2DSW *shape = NULL; @@ -169,7 +175,9 @@ void Physics2DServerSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 & cbk->invalid_by_dir++; return; } - if (cbk->valid_dir.dot((p_point_A - p_point_B).normalized()) < 0.7071) { + Vector2 rel_dir = (p_point_A - p_point_B).normalized(); + + if (cbk->valid_dir.dot(rel_dir) < 0.7071) { //sqrt(2)/2.0 - 45 degrees cbk->invalid_by_dir++; /* @@ -399,6 +407,8 @@ void Physics2DServerSW::area_set_shape_transform(RID p_area, int p_shape_idx, co void Physics2DServerSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) { + FLUSH_QUERY_CHECK + Area2DSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); @@ -469,6 +479,27 @@ ObjectID Physics2DServerSW::area_get_object_instance_id(RID p_area) const { return area->get_instance_id(); } +void Physics2DServerSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_ID) { + + if (space_owner.owns(p_area)) { + Space2DSW *space = space_owner.get(p_area); + p_area = space->get_default_area()->get_self(); + } + Area2DSW *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + area->set_canvas_instance_id(p_ID); +} +ObjectID Physics2DServerSW::area_get_canvas_instance_id(RID p_area) const { + + if (space_owner.owns(p_area)) { + Space2DSW *space = space_owner.get(p_area); + p_area = space->get_default_area()->get_self(); + } + Area2DSW *area = area_owner.get(p_area); + ERR_FAIL_COND_V(!area, 0); + return area->get_canvas_instance_id(); +} + void Physics2DServerSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { if (space_owner.owns(p_area)) { @@ -516,6 +547,8 @@ void Physics2DServerSW::area_set_pickable(RID p_area, bool p_pickable) { void Physics2DServerSW::area_set_monitorable(RID p_area, bool p_monitorable) { + FLUSH_QUERY_CHECK + Area2DSW *area = area_owner.get(p_area); ERR_FAIL_COND(!area); @@ -594,6 +627,8 @@ RID Physics2DServerSW::body_get_space(RID p_body) const { void Physics2DServerSW::body_set_mode(RID p_body, BodyMode p_mode) { + FLUSH_QUERY_CHECK + Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -696,6 +731,8 @@ void Physics2DServerSW::body_clear_shapes(RID p_body) { void Physics2DServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { + FLUSH_QUERY_CHECK + Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -744,6 +781,22 @@ uint32_t Physics2DServerSW::body_get_object_instance_id(RID p_body) const { return body->get_instance_id(); }; +void Physics2DServerSW::body_attach_canvas_instance_id(RID p_body, uint32_t p_ID) { + + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_canvas_instance_id(p_ID); +}; + +uint32_t Physics2DServerSW::body_get_canvas_instance_id(RID p_body) const { + + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_canvas_instance_id(); +}; + void Physics2DServerSW::body_set_collision_layer(RID p_body, uint32_t p_layer) { Body2DSW *body = body_owner.get(p_body); @@ -1309,6 +1362,8 @@ void Physics2DServerSW::flush_queries() { if (!active) return; + flushing_queries = true; + uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) { @@ -1317,6 +1372,8 @@ void Physics2DServerSW::flush_queries() { space->call_queries(); } + flushing_queries = false; + if (ScriptDebugger::get_singleton() && ScriptDebugger::get_singleton()->is_profiling()) { uint64_t total_time[Space2DSW::ELAPSED_TIME_MAX]; @@ -1395,6 +1452,7 @@ Physics2DServerSW::Physics2DServerSW() { active_objects = 0; collision_pairs = 0; using_threads = int(ProjectSettings::get_singleton()->get("physics/2d/thread_model")) == 2; + flushing_queries = false; }; Physics2DServerSW::~Physics2DServerSW(){ diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index d4fc44b1d7..4f33873219 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -54,6 +54,8 @@ class Physics2DServerSW : public Physics2DServer { bool using_threads; + bool flushing_queries; + Step2DSW *stepper; Set<const Space2DSW *> active_spaces; @@ -144,6 +146,9 @@ public: virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID); virtual ObjectID area_get_object_instance_id(RID p_area) const; + virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_ID); + virtual ObjectID area_get_canvas_instance_id(RID p_area) const; + virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value); virtual void area_set_transform(RID p_area, const Transform2D &p_transform); @@ -188,6 +193,9 @@ public: virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID); virtual uint32_t body_get_object_instance_id(RID p_body) const; + virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_ID); + virtual uint32_t body_get_canvas_instance_id(RID p_body) const; + virtual void body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode); virtual CCDMode body_get_continuous_collision_detection_mode(RID p_body) const; @@ -272,6 +280,8 @@ public: virtual void end_sync(); virtual void finish(); + virtual bool is_flushing_queries() const { return flushing_queries; } + int get_process_info(ProcessInfo p_info); Physics2DServerSW(); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index 5f5fd3866f..e736854077 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -154,6 +154,9 @@ public: FUNC2(area_attach_object_instance_id, RID, ObjectID); FUNC1RC(ObjectID, area_get_object_instance_id, RID); + FUNC2(area_attach_canvas_instance_id, RID, ObjectID); + FUNC1RC(ObjectID, area_get_canvas_instance_id, RID); + FUNC3(area_set_param, RID, AreaParameter, const Variant &); FUNC2(area_set_transform, RID, const Transform2D &); @@ -199,6 +202,9 @@ public: FUNC2(body_attach_object_instance_id, RID, uint32_t); FUNC1RC(uint32_t, body_get_object_instance_id, RID); + FUNC2(body_attach_canvas_instance_id, RID, uint32_t); + FUNC1RC(uint32_t, body_get_canvas_instance_id, RID); + FUNC2(body_set_continuous_collision_detection_mode, RID, CCDMode); FUNC1RC(CCDMode, body_get_continuous_collision_detection_mode, RID); @@ -306,6 +312,10 @@ public: virtual void flush_queries(); virtual void finish(); + virtual bool is_flushing_queries() const { + return physics_2d_server->is_flushing_queries(); + } + int get_process_info(ProcessInfo p_info) { return physics_2d_server->get_process_info(p_info); } diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index f36328c985..720742c198 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -31,9 +31,9 @@ #include "space_2d_sw.h" #include "collision_solver_2d_sw.h" +#include "core/os/os.h" #include "core/pair.h" #include "physics_2d_server_sw.h" - _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (!(p_object->get_collision_layer() & p_collision_mask)) { @@ -49,7 +49,7 @@ _FORCE_INLINE_ static bool _can_collide_with(CollisionObject2DSW *p_object, uint return true; } -int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) { +int Physics2DDirectSpaceStateSW::_intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) { if (p_result_max <= 0) return 0; @@ -75,6 +75,9 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe if (p_pick_point && !col_obj->is_pickable()) continue; + if (p_filter_by_canvas && col_obj->get_canvas_instance_id() != p_canvas_instance_id) + continue; + int shape_idx = space->intersection_query_subindex_results[i]; Shape2DSW *shape = col_obj->get_shape(shape_idx); @@ -100,6 +103,16 @@ int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeRe return cc; } +int Physics2DDirectSpaceStateSW::intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) { + + return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point); +} + +int Physics2DDirectSpaceStateSW::intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point) { + + return _intersect_point_impl(p_point, r_results, p_result_max, p_exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas, p_pick_point, true, p_canvas_instance_id); +} + bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { ERR_FAIL_COND_V(space->locked, false); @@ -352,6 +365,8 @@ struct _RestCallbackData2D { const CollisionObject2DSW *object; const CollisionObject2DSW *best_object; + int local_shape; + int best_local_shape; int shape; int best_shape; Vector2 best_contact; @@ -382,6 +397,7 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, rd->best_normal = contact_rel / len; rd->best_object = rd->object; rd->best_shape = rd->shape; + rd->best_local_shape = rd->local_shape; } bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { @@ -415,6 +431,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh rcd.valid_depth = 0; rcd.object = col_obj; rcd.shape = shape_idx; + rcd.local_shape = 0; bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin); if (!sc) continue; @@ -487,12 +504,23 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t Rect2 body_aabb; + bool shapes_found = false; + for (int i = 0; i < p_body->get_shape_count(); i++) { - if (i == 0) + if (p_body->is_shape_set_as_disabled(i)) + continue; + + if (!shapes_found) { body_aabb = p_body->get_shape_aabb(i); - else + shapes_found = true; + } else { body_aabb = body_aabb.merge(p_body->get_shape_aabb(i)); + } + } + + if (!shapes_found) { + return 0; } // Undo the currently transform the physics server is aware of and apply the provided one @@ -555,9 +583,11 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t } } + Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { - cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); + cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); cbk.valid_depth = p_margin; //only valid depth is the collision margin cbk.invalid_by_dir = 0; @@ -568,7 +598,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t } Shape2DSW *against_shape = col_obj->get_shape(shape_idx); - if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) { + if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) { if (cbk.amount > 0) { collided = true; } @@ -647,12 +677,23 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } Rect2 body_aabb; + bool shapes_found = false; + for (int i = 0; i < p_body->get_shape_count(); i++) { - if (i == 0) + if (p_body->is_shape_set_as_disabled(i)) + continue; + + if (!shapes_found) { body_aabb = p_body->get_shape_aabb(i); - else + shapes_found = true; + } else { body_aabb = body_aabb.merge(p_body->get_shape_aabb(i)); + } + } + + if (!shapes_found) { + return false; } // Undo the currently transform the physics server is aware of and apply the provided one @@ -663,6 +704,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs]; int excluded_shape_pair_count = 0; + float separation_margin = MIN(p_margin, MAX(0.0, p_motion.length() - CMP_EPSILON)); //don't separate by more than the intended motion + Transform2D body_transform = p_from; { @@ -710,24 +753,42 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } } + Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { - cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); + cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); + cbk.valid_depth = p_margin; //only valid depth is the collision margin cbk.invalid_by_dir = 0; + if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { + const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (b->get_mode() == Physics2DServer::BODY_MODE_KINEMATIC || b->get_mode() == Physics2DServer::BODY_MODE_RIGID) { + //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction + Vector2 lv = b->get_linear_velocity(); + //compute displacement from linear velocity + Vector2 motion = lv * Physics2DDirectBodyStateSW::singleton->step; + float motion_len = motion.length(); + motion.normalize(); + cbk.valid_depth += motion_len * MAX(motion.dot(-cbk.valid_dir), 0.0); + } + } } else { cbk.valid_dir = Vector2(); cbk.valid_depth = 0; cbk.invalid_by_dir = 0; } + int current_collisions = cbk.amount; + bool did_collide = false; + Shape2DSW *against_shape = col_obj->get_shape(shape_idx); - if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) { - collided = cbk.amount > 0; + if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, separation_margin)) { + did_collide = cbk.amount > current_collisions; } - if (!collided && cbk.invalid_by_dir > 0) { + if (!did_collide && cbk.invalid_by_dir > 0) { //this shape must be excluded if (excluded_shape_pair_count < max_excluded_shape_pairs) { ExcludedShapeSW esp; @@ -737,6 +798,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co excluded_shape_pairs[excluded_shape_pair_count++] = esp; } } + + if (did_collide) { + collided = true; + } } } @@ -824,14 +889,14 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co continue; } - Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx); + Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx); //test initial overlap, does it collide if going all the way? - if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) { + if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) { continue; } //test initial overlap - if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) { + if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, NULL, 0)) { if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) { continue; @@ -851,7 +916,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co real_t ofs = (low + hi) * 0.5; Vector2 sep = mnormal; //important optimization for this to work fast enough - bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_xform, Vector2(), NULL, NULL, &sep, 0); + bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * ofs, against_shape, col_obj_shape_xform, Vector2(), NULL, NULL, &sep, 0); if (collided) { @@ -869,12 +934,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co cbk.max = 1; cbk.amount = 0; cbk.ptr = cd; - cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); + cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); cbk.valid_depth = 10e20; Vector2 sep = mnormal; //important optimization for this to work fast enough - bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0); + bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0); if (!collided || cbk.amount == 0) { continue; } @@ -907,16 +972,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co bool collided = false; if (safe >= 1) { - //not collided - collided = false; - if (r_result) { - - r_result->motion = p_motion; - r_result->remainder = Vector2(); - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); - } + best_shape = -1; //no best shape with cast, reset to -1 + } - } else { + { //it collided, let's get the rest info in unsafe advance Transform2D ugt = body_transform; @@ -927,52 +986,61 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co rcd.best_object = NULL; rcd.best_shape = 0; - Transform2D body_shape_xform = ugt * p_body->get_shape_transform(best_shape); - Shape2DSW *body_shape = p_body->get_shape(best_shape); + //optimization + int from_shape = best_shape != -1 ? best_shape : 0; + int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); - body_aabb.position += p_motion * unsafe; + for (int j = from_shape; j < to_shape; j++) { + Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j); + Shape2DSW *body_shape = p_body->get_shape(j); - int amount = _cull_aabb_for_body(p_body, body_aabb); + body_aabb.position += p_motion * unsafe; + + int amount = _cull_aabb_for_body(p_body, body_aabb); - for (int i = 0; i < amount; i++) { + for (int i = 0; i < amount; i++) { - const CollisionObject2DSW *col_obj = intersection_query_results[i]; - int shape_idx = intersection_query_subindex_results[i]; + const CollisionObject2DSW *col_obj = intersection_query_results[i]; + int shape_idx = intersection_query_subindex_results[i]; - if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) { - const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); - if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) { - continue; + if (CollisionObject2DSW::TYPE_BODY == col_obj->get_type()) { + const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (p_infinite_inertia && Physics2DServer::BODY_MODE_STATIC != b->get_mode() && Physics2DServer::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } } - } - Shape2DSW *against_shape = col_obj->get_shape(shape_idx); + Shape2DSW *against_shape = col_obj->get_shape(shape_idx); - bool excluded = false; - for (int k = 0; k < excluded_shape_pair_count; k++) { + bool excluded = false; + for (int k = 0; k < excluded_shape_pair_count; k++) { - if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == shape_idx) { - excluded = true; - break; + if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == shape_idx) { + excluded = true; + break; + } } - } - if (excluded) - continue; + if (excluded) + continue; - if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { + Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); - rcd.valid_dir = body_shape_xform.get_axis(1).normalized(); - rcd.valid_depth = 10e20; - } else { - rcd.valid_dir = Vector2(); - rcd.valid_depth = 0; - } + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { - rcd.object = col_obj; - rcd.shape = shape_idx; - bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin); - if (!sc) - continue; + rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); + rcd.valid_depth = 10e20; + } else { + rcd.valid_dir = Vector2(); + rcd.valid_depth = 0; + } + + rcd.object = col_obj; + rcd.shape = shape_idx; + rcd.local_shape = j; + bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, NULL, p_margin); + if (!sc) + continue; + } } if (rcd.best_len != 0) { @@ -981,7 +1049,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co r_result->collider = rcd.best_object->get_self(); r_result->collider_id = rcd.best_object->get_instance_id(); r_result->collider_shape = rcd.best_shape; - r_result->collision_local_shape = best_shape; + r_result->collision_local_shape = rcd.best_local_shape; r_result->collision_normal = rcd.best_normal; r_result->collision_point = rcd.best_contact; r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); @@ -996,16 +1064,14 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } collided = true; - } else { - if (r_result) { + } + } - r_result->motion = p_motion; - r_result->remainder = Vector2(); - r_result->motion += (body_transform.get_origin() - p_from.get_origin()); - } + if (!collided && r_result) { - collided = false; - } + r_result->motion = p_motion; + r_result->remainder = Vector2(); + r_result->motion += (body_transform.get_origin() - p_from.get_origin()); } return collided; @@ -1233,6 +1299,7 @@ Space2DSW::Space2DSW() { body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0); body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI)); body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5); + ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::REAL, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); broadphase = BroadPhase2DSW::create_func(); broadphase->set_pair_callback(_broadphase_pair, this); diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index c894eb9c40..bf4ea12eb5 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -45,10 +45,13 @@ class Physics2DDirectSpaceStateSW : public Physics2DDirectSpaceState { GDCLASS(Physics2DDirectSpaceStateSW, Physics2DDirectSpaceState); + int _intersect_point_impl(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_pick_point, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0); + public: Space2DSW *space; virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false); + virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false); virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index 3ca6e29f0b..2ed8a4c478 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -328,7 +328,7 @@ Array Physics2DDirectSpaceState::_cast_motion(const Ref<Physics2DShapeQueryParam return ret; } -Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) { +Array Physics2DDirectSpaceState::_intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas, ObjectID p_canvas_instance_id) { Set<RID> exclude; for (int i = 0; i < p_exclude.size(); i++) @@ -337,7 +337,12 @@ Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_ Vector<ShapeResult> ret; ret.resize(p_max_results); - int rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas); + int rc; + if (p_filter_by_canvas) + rc = intersect_point(p_point, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas); + else + rc = intersect_point_on_canvas(p_point, p_canvas_instance_id, ret.ptrw(), ret.size(), exclude, p_layers, p_collide_with_bodies, p_collide_with_areas); + if (rc == 0) return Array(); @@ -356,6 +361,16 @@ Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_ return r; } +Array Physics2DDirectSpaceState::_intersect_point(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) { + + return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas); +} + +Array Physics2DDirectSpaceState::_intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) { + + return _intersect_point_impl(p_point, p_max_results, p_exclude, p_layers, p_collide_with_bodies, p_collide_with_areas, true, p_canvas_intance_id); +} + Array Physics2DDirectSpaceState::_collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); @@ -400,6 +415,7 @@ Physics2DDirectSpaceState::Physics2DDirectSpaceState() { void Physics2DDirectSpaceState::_bind_methods() { ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_layer", "collide_with_bodies", "collide_with_areas"), &Physics2DDirectSpaceState::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &Physics2DDirectSpaceState::_intersect_shape, DEFVAL(32)); ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &Physics2DDirectSpaceState::_cast_motion); @@ -575,6 +591,9 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &Physics2DServer::area_attach_object_instance_id); ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &Physics2DServer::area_get_object_instance_id); + ClassDB::bind_method(D_METHOD("area_attach_canvas_instance_id", "area", "id"), &Physics2DServer::area_attach_canvas_instance_id); + ClassDB::bind_method(D_METHOD("area_get_canvas_instance_id", "area"), &Physics2DServer::area_get_canvas_instance_id); + ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_monitor_callback); ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &Physics2DServer::area_set_area_monitor_callback); ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &Physics2DServer::area_set_monitorable); @@ -606,6 +625,9 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &Physics2DServer::body_attach_object_instance_id); ClassDB::bind_method(D_METHOD("body_get_object_instance_id", "body"), &Physics2DServer::body_get_object_instance_id); + ClassDB::bind_method(D_METHOD("body_attach_canvas_instance_id", "body", "id"), &Physics2DServer::body_attach_canvas_instance_id); + ClassDB::bind_method(D_METHOD("body_get_canvas_instance_id", "body"), &Physics2DServer::body_get_canvas_instance_id); + ClassDB::bind_method(D_METHOD("body_set_continuous_collision_detection_mode", "body", "mode"), &Physics2DServer::body_set_continuous_collision_detection_mode); ClassDB::bind_method(D_METHOD("body_get_continuous_collision_detection_mode", "body"), &Physics2DServer::body_get_continuous_collision_detection_mode); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 7c23fcdaea..32e1dd1a08 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -147,8 +147,9 @@ class Physics2DDirectSpaceState : public Object { GDCLASS(Physics2DDirectSpaceState, Object); Dictionary _intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); - Array _intersect_point(const Vector2 &p_point, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + Array _intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_intance_id, int p_max_results = 32, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_layers = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + Array _intersect_point_impl(const Vector2 &p_point, int p_max_results, const Vector<RID> &p_exclud, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas, bool p_filter_by_canvas = false, ObjectID p_canvas_instance_id = 0); Array _intersect_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32); Array _cast_motion(const Ref<Physics2DShapeQueryParameters> &p_shape_query); Array _collide_shape(const Ref<Physics2DShapeQueryParameters> &p_shape_query, int p_max_results = 32); @@ -181,6 +182,7 @@ public: }; virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; + virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, float p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; @@ -348,6 +350,9 @@ public: virtual void area_attach_object_instance_id(RID p_area, ObjectID p_ID) = 0; virtual ObjectID area_get_object_instance_id(RID p_area) const = 0; + virtual void area_attach_canvas_instance_id(RID p_area, ObjectID p_ID) = 0; + virtual ObjectID area_get_canvas_instance_id(RID p_area) const = 0; + virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0; virtual void area_set_transform(RID p_area, const Transform2D &p_transform) = 0; @@ -401,6 +406,9 @@ public: virtual void body_attach_object_instance_id(RID p_body, uint32_t p_ID) = 0; virtual uint32_t body_get_object_instance_id(RID p_body) const = 0; + virtual void body_attach_canvas_instance_id(RID p_body, uint32_t p_ID) = 0; + virtual uint32_t body_get_canvas_instance_id(RID p_body) const = 0; + enum CCDMode { CCD_MODE_DISABLED, CCD_MODE_CAST_RAY, @@ -576,6 +584,8 @@ public: virtual void end_sync() = 0; virtual void finish() = 0; + virtual bool is_flushing_queries() const = 0; + enum ProcessInfo { INFO_ACTIVE_OBJECTS, diff --git a/servers/physics_server.h b/servers/physics_server.h index d80d76305a..15b353f768 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -697,6 +697,9 @@ public: G6DOF_JOINT_LINEAR_DAMPING, G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY, G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT, + G6DOF_JOINT_LINEAR_SPRING_STIFFNESS, + G6DOF_JOINT_LINEAR_SPRING_DAMPING, + G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT, G6DOF_JOINT_ANGULAR_LOWER_LIMIT, G6DOF_JOINT_ANGULAR_UPPER_LIMIT, G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, @@ -706,6 +709,9 @@ public: G6DOF_JOINT_ANGULAR_ERP, G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY, G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT, + G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS, + G6DOF_JOINT_ANGULAR_SPRING_DAMPING, + G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT, G6DOF_JOINT_MAX }; @@ -713,6 +719,8 @@ public: G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, + G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING, + G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING, G6DOF_JOINT_FLAG_ENABLE_MOTOR, G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR, G6DOF_JOINT_FLAG_MAX @@ -744,6 +752,8 @@ public: virtual void flush_queries() = 0; virtual void finish() = 0; + virtual bool is_flushing_queries() const = 0; + enum ProcessInfo { INFO_ACTIVE_OBJECTS, diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 8c3736a1bf..4329203ccb 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -73,7 +73,7 @@ public: virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) = 0; virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0; - virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0; + virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0; virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0; virtual bool is_environment(RID p_env) = 0; @@ -120,9 +120,7 @@ public: Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader virtual void base_removed() = 0; - virtual void base_changed() = 0; - virtual void base_material_changed() = 0; - + virtual void base_changed(bool p_aabb, bool p_materials) = 0; InstanceBase() : dependency_item(this) { @@ -520,6 +518,8 @@ public: virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; virtual void particles_restart(RID p_particles) = 0; + virtual bool particles_is_inactive(RID p_particles) const = 0; + virtual void particles_set_draw_order(RID p_particles, VS::ParticlesDrawOrder p_order) = 0; virtual void particles_set_draw_passes(RID p_particles, int p_count) = 0; @@ -800,8 +800,6 @@ public: RID particles; RID texture; RID normal_map; - int h_frames; - int v_frames; CommandParticles() { type = TYPE_PARTICLES; } }; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 67a810bf1c..1acec7ccaf 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -131,7 +131,6 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "TYPE_USAMPLER3D", "TYPE_SAMPLERCUBE", "INTERPOLATION_FLAT", - "INTERPOLATION_NO_PERSPECTIVE", "INTERPOLATION_SMOOTH", "PRECISION_LOW", "PRECISION_MID", @@ -271,7 +270,6 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_USAMPLER3D, "usampler3D" }, { TK_TYPE_SAMPLERCUBE, "samplerCube" }, { TK_INTERPOLATION_FLAT, "flat" }, - { TK_INTERPOLATION_NO_PERSPECTIVE, "noperspective" }, { TK_INTERPOLATION_SMOOTH, "smooth" }, { TK_PRECISION_LOW, "lowp" }, { TK_PRECISION_MID, "mediump" }, @@ -691,6 +689,30 @@ String ShaderLanguage::token_debug(const String &p_code) { return output; } +bool ShaderLanguage::is_token_variable_datatype(TokenType p_type) { + return ( + p_type == TK_TYPE_VOID || + p_type == TK_TYPE_BOOL || + p_type == TK_TYPE_BVEC2 || + p_type == TK_TYPE_BVEC3 || + p_type == TK_TYPE_BVEC4 || + p_type == TK_TYPE_INT || + p_type == TK_TYPE_IVEC2 || + p_type == TK_TYPE_IVEC3 || + p_type == TK_TYPE_IVEC4 || + p_type == TK_TYPE_UINT || + p_type == TK_TYPE_UVEC2 || + p_type == TK_TYPE_UVEC3 || + p_type == TK_TYPE_UVEC4 || + p_type == TK_TYPE_FLOAT || + p_type == TK_TYPE_VEC2 || + p_type == TK_TYPE_VEC3 || + p_type == TK_TYPE_VEC4 || + p_type == TK_TYPE_MAT2 || + p_type == TK_TYPE_MAT3 || + p_type == TK_TYPE_MAT4); +} + bool ShaderLanguage::is_token_datatype(TokenType p_type) { return ( @@ -735,7 +757,6 @@ bool ShaderLanguage::is_token_interpolation(TokenType p_type) { return ( p_type == TK_INTERPOLATION_FLAT || - p_type == TK_INTERPOLATION_NO_PERSPECTIVE || p_type == TK_INTERPOLATION_SMOOTH); } @@ -743,8 +764,6 @@ ShaderLanguage::DataInterpolation ShaderLanguage::get_token_interpolation(TokenT if (p_type == TK_INTERPOLATION_FLAT) return INTERPOLATION_FLAT; - else if (p_type == TK_INTERPOLATION_NO_PERSPECTIVE) - return INTERPOLATION_NO_PERSPECTIVE; else return INTERPOLATION_SMOOTH; } @@ -1196,6 +1215,15 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_MAT4 && nb == TYPE_VEC4) { valid = true; ret_type = TYPE_MAT4; + } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC2 && nb == TYPE_MAT2) { + valid = true; + ret_type = TYPE_VEC2; + } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC3 && nb == TYPE_MAT3) { + valid = true; + ret_type = TYPE_VEC3; + } else if (p_op->op == OP_ASSIGN_MUL && na == TYPE_VEC4 && nb == TYPE_MAT4) { + valid = true; + ret_type = TYPE_VEC4; } } break; case OP_ASSIGN_BIT_AND: @@ -2013,6 +2041,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { }; +const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { + //constructors + { "modf", 1 }, + { NULL, 0 } +}; + bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type) { ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, NULL); @@ -2056,6 +2090,41 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p if (!fail) { + //make sure its not an out argument used in the wrong way + int outarg_idx = 0; + while (builtin_func_out_args[outarg_idx].name) { + + if (String(name) == builtin_func_out_args[outarg_idx].name) { + int arg_idx = builtin_func_out_args[outarg_idx].argument; + + if (arg_idx < argcount) { + + if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE) { + _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable"); + return false; + } + StringName var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name; + + const BlockNode *b = p_block; + bool valid = false; + while (b) { + if (b->variables.has(var_name)) { + valid = true; + break; + } + b = b->parent_block; + } + + if (!valid) { + _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable"); + return false; + } + } + } + + outarg_idx++; + } + if (r_ret_type) *r_ret_type = builtin_func_defs[idx].rettype; @@ -2288,7 +2357,7 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) { p_type == TYPE_SAMPLERCUBE; } -Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type) { +Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { if (p_value.size() > 0) { Variant value; switch (p_type) { @@ -2332,7 +2401,11 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); break; case ShaderLanguage::TYPE_VEC4: - value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + } else { + value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real)); + } break; case ShaderLanguage::TYPE_MAT2: value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0)); @@ -2498,7 +2571,7 @@ bool ShaderLanguage::_get_completable_identifier(BlockNode *p_block, CompletionT identifier = StringName(); - TkPos pos; + TkPos pos = { 0, 0 }; Token tk = _get_token(); @@ -3506,6 +3579,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha nv.sint = -cn->values[i].sint; } break; case TYPE_UINT: { + // FIXME: This can't work on uint nv.uint = -cn->values[i].uint; } break; case TYPE_FLOAT: { @@ -3562,6 +3636,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } } + if (!is_token_variable_datatype(tk.type)) { + _set_error("Invalid data type for variable (samplers not allowed)"); + return ERR_PARSE_ERROR; + } + DataType type = get_token_datatype(tk.type); tk = _get_token(); @@ -4217,6 +4296,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } + if (!is_token_variable_datatype(tk.type)) { + _set_error("Invalid data type for function return (samplers not allowed)"); + return ERR_PARSE_ERROR; + } + type = get_token_datatype(tk.type); _get_completable_identifier(NULL, COMPLETION_MAIN_FUNCTION, name); diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 08c4d06992..2d1851928e 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -80,7 +80,6 @@ public: TK_TYPE_USAMPLER3D, TK_TYPE_SAMPLERCUBE, TK_INTERPOLATION_FLAT, - TK_INTERPOLATION_NO_PERSPECTIVE, TK_INTERPOLATION_SMOOTH, TK_PRECISION_LOW, TK_PRECISION_MID, @@ -210,7 +209,6 @@ public: enum DataInterpolation { INTERPOLATION_FLAT, - INTERPOLATION_NO_PERSPECTIVE, INTERPOLATION_SMOOTH, }; @@ -333,6 +331,7 @@ public: virtual DataType get_datatype() const { return datatype_cache; } VariableNode() { + type = TYPE_VARIABLE; datatype_cache = TYPE_VOID; } @@ -534,6 +533,7 @@ public: static String get_token_text(Token p_token); static bool is_token_datatype(TokenType p_type); + static bool is_token_variable_datatype(TokenType p_type); static DataType get_token_datatype(TokenType p_type); static bool is_token_interpolation(TokenType p_type); static DataInterpolation get_token_interpolation(TokenType p_type); @@ -548,7 +548,7 @@ public: static int get_cardinality(DataType p_type); static bool is_scalar_type(DataType p_type); static bool is_sampler_type(DataType p_type); - static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type); + static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); static void get_keyword_list(List<String> *r_keywords); static void get_builtin_funcs(List<String> *r_keywords); @@ -642,6 +642,12 @@ private: const DataType args[MAX_ARGS]; }; + struct BuiltinFuncOutArgs { //arguments used as out in built in funcions + + const char *name; + int argument; + }; + CompletionType completion_type; int completion_line; BlockNode *completion_block; @@ -652,6 +658,7 @@ private: bool _get_completable_identifier(BlockNode *p_block, CompletionType p_type, StringName &identifier); static const BuiltinFuncDef builtin_func_defs[]; + static const BuiltinFuncOutArgs builtin_func_out_args[]; bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type); bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = NULL); diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 69acf52e17..baafe2f8d0 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -199,6 +199,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["INSTANCE_CUSTOM"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 16cda0326d..734c295a72 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -51,6 +51,23 @@ void VisualServerCanvas::_render_canvas_item_tree(Item *p_canvas_item, const Tra } } +void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item **r_items, int &r_index) { + int child_item_count = p_canvas_item->child_items.size(); + VisualServerCanvas::Item **child_items = p_canvas_item->child_items.ptrw(); + for (int i = 0; i < child_item_count; i++) { + if (r_items) { + r_items[r_index] = child_items[i]; + child_items[i]->ysort_xform = p_transform; + child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.elements[2]); + } + + r_index++; + + if (child_items[i]->sort_y) + _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, r_items, r_index); + } +} + void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) { Item *ci = p_canvas_item; @@ -58,10 +75,10 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor if (!ci->visible) return; - if (p_canvas_item->children_order_dirty) { + if (ci->children_order_dirty) { - p_canvas_item->child_items.sort_custom<ItemIndexSort>(); - p_canvas_item->children_order_dirty = false; + ci->child_items.sort_custom<ItemIndexSort>(); + ci->children_order_dirty = false; } Rect2 rect = ci->get_rect(); @@ -82,8 +99,7 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor return; int child_item_count = ci->child_items.size(); - Item **child_items = (Item **)alloca(child_item_count * sizeof(Item *)); - copymem(child_items, ci->child_items.ptr(), child_item_count * sizeof(Item *)); + Item **child_items = ci->child_items.ptrw(); if (ci->clip) { if (p_canvas_clip != NULL) { @@ -99,6 +115,17 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor if (ci->sort_y) { + if (ci->ysort_children_count == -1) { + ci->ysort_children_count = 0; + _collect_ysort_children(ci, Transform2D(), NULL, ci->ysort_children_count); + } + + child_item_count = ci->ysort_children_count; + child_items = (Item **)alloca(child_item_count * sizeof(Item *)); + + int i = 0; + _collect_ysort_children(ci, Transform2D(), child_items, i); + SortArray<Item *, ItemPtrSort> sorter; sorter.sort(child_items, child_item_count); } @@ -110,9 +137,13 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor for (int i = 0; i < child_item_count; i++) { - if (!child_items[i]->behind) + if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) continue; - _render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + if (ci->sort_y) { + _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + } else { + _render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + } } if (ci->copy_back_buffer) { @@ -148,9 +179,13 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor for (int i = 0; i < child_item_count; i++) { - if (child_items[i]->behind) + if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y)) continue; - _render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + if (ci->sort_y) { + _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + } else { + _render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + } } } @@ -300,6 +335,12 @@ void VisualServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) { Item *item_owner = canvas_item_owner.get(canvas_item->parent); item_owner->child_items.erase(canvas_item); + + Item *ysort_owner = item_owner; + while (ysort_owner && ysort_owner->sort_y) { + item_owner->ysort_children_count = -1; + ysort_owner = canvas_item_owner.getornull(ysort_owner->parent); + } } canvas_item->parent = RID(); @@ -319,6 +360,12 @@ void VisualServerCanvas::canvas_item_set_parent(RID p_item, RID p_parent) { item_owner->child_items.push_back(canvas_item); item_owner->children_order_dirty = true; + Item *ysort_owner = item_owner; + while (ysort_owner && ysort_owner->sort_y) { + item_owner->ysort_children_count = -1; + ysort_owner = canvas_item_owner.getornull(ysort_owner->parent); + } + } else { ERR_EXPLAIN("Invalid parent"); @@ -689,7 +736,7 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2 if (indices.empty()) { ERR_EXPLAIN("Bad Polygon!"); - ERR_FAIL_V(); + ERR_FAIL(); } Item::CommandPolygon *polygon = memnew(Item::CommandPolygon); @@ -776,7 +823,7 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID canvas_item->commands.push_back(m); } -void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames) { +void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -786,8 +833,6 @@ void VisualServerCanvas::canvas_item_add_particles(RID p_item, RID p_particles, part->particles = p_particles; part->texture = p_texture; part->normal_map = p_normal; - part->h_frames = p_h_frames; - part->v_frames = p_v_frames; //take the chance and request processing for them, at least once until they become visible again VSG::storage->particles_request_process(p_particles); @@ -828,6 +873,7 @@ void VisualServerCanvas::canvas_item_set_sort_children_by_y(RID p_item, bool p_e ERR_FAIL_COND(!canvas_item); canvas_item->sort_y = p_enable; + canvas_item->ysort_children_count = -1; } void VisualServerCanvas::canvas_item_set_z_index(RID p_item, int p_z) { @@ -1304,6 +1350,12 @@ bool VisualServerCanvas::free(RID p_rid) { Item *item_owner = canvas_item_owner.get(canvas_item->parent); item_owner->child_items.erase(canvas_item); + + Item *ysort_owner = item_owner; + while (ysort_owner && ysort_owner->sort_y) { + item_owner->ysort_children_count = -1; + ysort_owner = canvas_item_owner.getornull(ysort_owner->parent); + } } } diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index 966b51d341..4b7422b15a 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -48,6 +48,9 @@ public: bool use_parent_material; int index; bool children_order_dirty; + int ysort_children_count; + Transform2D ysort_xform; + Vector2 ysort_pos; Vector<Item *> child_items; @@ -61,6 +64,9 @@ public: use_parent_material = false; z_relative = true; index = 0; + ysort_children_count = -1; + ysort_xform = Transform2D(); + ysort_pos = Vector2(); } }; @@ -76,10 +82,10 @@ public: _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const { - if (Math::abs(p_left->xform.elements[2].y - p_right->xform.elements[2].y) < CMP_EPSILON) - return p_left->xform.elements[2].x < p_right->xform.elements[2].x; + if (Math::abs(p_left->ysort_pos.y - p_right->ysort_pos.y) < CMP_EPSILON) + return p_left->ysort_pos.x < p_right->ysort_pos.x; else - return p_left->xform.elements[2].y < p_right->xform.elements[2].y; + return p_left->ysort_pos.y < p_right->ysort_pos.y; } }; @@ -186,7 +192,7 @@ public: void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()); void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()); - void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal, int p_h_frames, int p_v_frames); + void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal); void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 62ba2eab69..d37fe28ac6 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -474,7 +474,7 @@ public: BIND2(viewport_set_transparent_background, RID, bool) BIND2(viewport_set_global_canvas_transform, RID, const Transform2D &) - BIND3(viewport_set_canvas_layer, RID, RID, int) + BIND4(viewport_set_canvas_stacking, RID, RID, int, int) BIND2(viewport_set_shadow_atlas_size, RID, int) BIND3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) BIND2(viewport_set_msaa, RID, ViewportMSAA) @@ -511,7 +511,7 @@ public: BIND6(environment_set_adjustment, RID, bool, float, float, float, RID) BIND5(environment_set_fog, RID, bool, const Color &, const Color &, float) - BIND6(environment_set_fog_depth, RID, bool, float, float, bool, float) + BIND7(environment_set_fog_depth, RID, bool, float, float, float, bool, float) BIND5(environment_set_fog_height, RID, bool, float, float, float) /* SCENARIO API */ @@ -599,7 +599,7 @@ public: BIND10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID) BIND4(canvas_item_add_mesh, RID, const RID &, RID, RID) BIND4(canvas_item_add_multimesh, RID, RID, RID, RID) - BIND6(canvas_item_add_particles, RID, RID, RID, RID, int, int) + BIND4(canvas_item_add_particles, RID, RID, RID, RID) BIND2(canvas_item_add_set_transform, RID, const Transform2D &) BIND2(canvas_item_add_clip_ignore, RID, bool) BIND2(canvas_item_set_sort_children_by_y, RID, bool) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 654994b83f..1deca7bc66 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -601,8 +601,9 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf Instance *instance = instance_owner.get(p_instance); ERR_FAIL_COND(!instance); - if (instance->update_item.in_list()) { - _update_dirty_instance(instance); + if (instance->base_type == VS::INSTANCE_MESH) { + //may not have been updated yet + instance->materials.resize(VSG::storage->mesh_get_surface_count(instance->base)); } ERR_FAIL_INDEX(p_surface, instance->materials.size()); @@ -611,7 +612,7 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf VSG::storage->material_remove_instance_owner(instance->materials[p_surface], instance); } instance->materials.write[p_surface] = p_material; - instance->base_material_changed(); + instance->base_changed(false, true); if (instance->materials[p_surface].is_valid()) { VSG::storage->material_add_instance_owner(instance->materials[p_surface], instance); @@ -839,7 +840,7 @@ void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instanc ERR_FAIL_COND(!instance); instance->cast_shadows = p_shadow_casting_setting; - instance->base_material_changed(); // to actually compute if shadows are visible or not + instance->base_changed(false, true); // to actually compute if shadows are visible or not } void VisualServerScene::instance_geometry_set_material_override(RID p_instance, RID p_material) { @@ -850,7 +851,7 @@ void VisualServerScene::instance_geometry_set_material_override(RID p_instance, VSG::storage->material_remove_instance_owner(instance->material_override, instance); } instance->material_override = p_material; - instance->base_material_changed(); + instance->base_changed(false, true); if (instance->material_override.is_valid()) { VSG::storage->material_add_instance_owner(instance->material_override, instance); @@ -1263,13 +1264,15 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) } } -void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) { +bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); Transform light_transform = p_instance->transform; light_transform.orthonormalize(); //scale does not count on lights + bool animated_material_found = false; + switch (VSG::storage->light_get_type(p_instance->base)) { case VS::LIGHT_DIRECTIONAL: { @@ -1302,6 +1305,10 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons continue; } + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + float max, min; instance->transformed_aabb.project_range_in_plane(base, min, max); @@ -1557,6 +1564,10 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); j--; } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } + instance->depth = near_plane.distance_to(instance->transform.origin); instance->depth_layer = 0; } @@ -1608,6 +1619,9 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); j--; } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } instance->depth = near_plane.distance_to(instance->transform.origin); instance->depth_layer = 0; } @@ -1644,6 +1658,9 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons SWAP(instance_shadow_cull_result[j], instance_shadow_cull_result[cull_count]); j--; } else { + if (static_cast<InstanceGeometryData *>(instance->base_data)->material_is_animated) { + animated_material_found = true; + } instance->depth = near_plane.distance_to(instance->transform.origin); instance->depth_layer = 0; } @@ -1654,6 +1671,8 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons } break; } + + return animated_material_found; } void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { @@ -1893,9 +1912,14 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca if (ins->base_type == VS::INSTANCE_PARTICLES) { //particles visible? process them - VSG::storage->particles_request_process(ins->base); - //particles visible? request redraw - VisualServerRaster::redraw_request(); + if (VSG::storage->particles_is_inactive(ins->base)) { + //but if nothing is going on, don't do it. + keep = false; + } else { + VSG::storage->particles_request_process(ins->base); + //particles visible? request redraw + VisualServerRaster::redraw_request(); + } } if (geom->lighting_dirty) { @@ -2095,7 +2119,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca if (redraw) { //must redraw! - _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario); + light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_shadow_atlas, scenario); } } } @@ -3243,11 +3267,13 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); bool can_cast_shadows = true; + bool is_animated = false; if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) { can_cast_shadows = false; } else if (p_instance->material_override.is_valid()) { can_cast_shadows = VSG::storage->material_casts_shadows(p_instance->material_override); + is_animated = VSG::storage->material_is_animated(p_instance->material_override); } else { if (p_instance->base_type == VS::INSTANCE_MESH) { @@ -3262,12 +3288,15 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (!mat.is_valid()) { cast_shadows = true; - break; - } + } else { - if (VSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - break; + if (VSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + + if (VSG::storage->material_is_animated(mat)) { + is_animated = true; + } } } @@ -3289,12 +3318,15 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (!mat.is_valid()) { cast_shadows = true; - break; - } - if (VSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - break; + } else { + + if (VSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + if (VSG::storage->material_is_animated(mat)) { + is_animated = true; + } } } @@ -3311,6 +3343,10 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { } else { can_cast_shadows = false; } + + if (mat.is_valid() && VSG::storage->material_is_animated(mat)) { + is_animated = true; + } } else if (p_instance->base_type == VS::INSTANCE_PARTICLES) { bool cast_shadows = false; @@ -3330,12 +3366,15 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (!mat.is_valid()) { cast_shadows = true; - break; - } + } else { - if (VSG::storage->material_casts_shadows(mat)) { - cast_shadows = true; - break; + if (VSG::storage->material_casts_shadows(mat)) { + cast_shadows = true; + } + + if (VSG::storage->material_is_animated(mat)) { + is_animated = true; + } } } } @@ -3355,6 +3394,8 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { geom->can_cast_shadows = can_cast_shadows; } + + geom->material_is_animated = is_animated; } } diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 0d4737f268..38c5258116 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -192,14 +192,9 @@ public: singleton->instance_set_base(self, RID()); } - virtual void base_changed() { + virtual void base_changed(bool p_aabb, bool p_materials) { - singleton->_instance_queue_update(this, true, true); - } - - virtual void base_material_changed() { - - singleton->_instance_queue_update(this, false, true); + singleton->_instance_queue_update(this, p_aabb, p_materials); } Instance() : @@ -247,6 +242,7 @@ public: List<Instance *> lighting; bool lighting_dirty; bool can_cast_shadows; + bool material_is_animated; List<Instance *> reflection_probes; bool reflection_dirty; @@ -261,6 +257,7 @@ public: lighting_dirty = false; reflection_dirty = true; can_cast_shadows = true; + material_is_animated = true; gi_probes_dirty = true; } }; @@ -488,7 +485,7 @@ public: _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); - _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); + _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe); void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index b286533590..571b71db85 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -137,7 +137,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E } } - canvas_map[Viewport::CanvasKey(E->key(), E->get().layer)] = &E->get(); + canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get(); } if (lights_with_shadow) { @@ -176,7 +176,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E VSG::rasterizer->restore_render_target(); - if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().layer > scenario_canvas_max_layer) { + if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) { Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); if (!can_draw_3d) { @@ -209,7 +209,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect); i++; - if (scenario_draw_canvas_bg && E->key().layer >= scenario_canvas_max_layer) { + if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); if (!can_draw_3d) { @@ -496,6 +496,7 @@ void VisualServerViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) canvas->viewports.insert(p_viewport); viewport->canvas_map[p_canvas] = Viewport::CanvasData(); viewport->canvas_map[p_canvas].layer = 0; + viewport->canvas_map[p_canvas].sublayer = 0; viewport->canvas_map[p_canvas].canvas = canvas; } @@ -534,13 +535,14 @@ void VisualServerViewport::viewport_set_global_canvas_transform(RID p_viewport, viewport->global_transform = p_transform; } -void VisualServerViewport::viewport_set_canvas_layer(RID p_viewport, RID p_canvas, int p_layer) { +void VisualServerViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas)); viewport->canvas_map[p_canvas].layer = p_layer; + viewport->canvas_map[p_canvas].sublayer = p_sublayer; } void VisualServerViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size) { diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index cb7912d6f4..66baa48458 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -78,17 +78,21 @@ public: struct CanvasKey { - int layer; + int64_t stacking; RID canvas; bool operator<(const CanvasKey &p_canvas) const { - if (layer == p_canvas.layer) return canvas < p_canvas.canvas; - return layer < p_canvas.layer; + if (stacking == p_canvas.stacking) + return canvas < p_canvas.canvas; + return stacking < p_canvas.stacking; + } + CanvasKey() { + stacking = 0; } - CanvasKey() { layer = 0; } - CanvasKey(const RID &p_canvas, int p_layer) { + CanvasKey(const RID &p_canvas, int p_layer, int p_sublayer) { canvas = p_canvas; - layer = p_layer; + stacking = ((int64_t)p_layer << 32) + p_sublayer; } + int get_layer() const { return stacking >> 32; } }; struct CanvasData { @@ -96,6 +100,7 @@ public: CanvasBase *canvas; Transform2D transform; int layer; + int sublayer; }; Transform2D global_transform; @@ -176,7 +181,7 @@ public: void viewport_set_transparent_background(RID p_viewport, bool p_enabled); void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform); - void viewport_set_canvas_layer(RID p_viewport, RID p_canvas, int p_layer); + void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer); void viewport_set_shadow_atlas_size(RID p_viewport, int p_size); void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index e4d69121f0..1aeb2756ba 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -400,7 +400,7 @@ public: FUNC2(viewport_set_transparent_background, RID, bool) FUNC2(viewport_set_global_canvas_transform, RID, const Transform2D &) - FUNC3(viewport_set_canvas_layer, RID, RID, int) + FUNC4(viewport_set_canvas_stacking, RID, RID, int, int) FUNC2(viewport_set_shadow_atlas_size, RID, int) FUNC3(viewport_set_shadow_atlas_quadrant_subdivision, RID, int, int) FUNC2(viewport_set_msaa, RID, ViewportMSAA) @@ -437,7 +437,7 @@ public: FUNC6(environment_set_adjustment, RID, bool, float, float, float, RID) FUNC5(environment_set_fog, RID, bool, const Color &, const Color &, float) - FUNC6(environment_set_fog_depth, RID, bool, float, float, bool, float) + FUNC7(environment_set_fog_depth, RID, bool, float, float, float, bool, float) FUNC5(environment_set_fog_height, RID, bool, float, float, float) FUNCRID(scenario) @@ -516,7 +516,7 @@ public: FUNC10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID) FUNC4(canvas_item_add_mesh, RID, const RID &, RID, RID) FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID) - FUNC6(canvas_item_add_particles, RID, RID, RID, RID, int, int) + FUNC4(canvas_item_add_particles, RID, RID, RID, RID) FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) FUNC2(canvas_item_add_clip_ignore, RID, bool) FUNC2(canvas_item_set_sort_children_by_y, RID, bool) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 9d684d33d6..e1db123f58 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -343,7 +343,7 @@ RID VisualServer::get_white_texture() { #define SMALL_VEC2 Vector2(0.00001, 0.00001) #define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001) -Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> r_bone_aabb) { +Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) { PoolVector<uint8_t>::Write vw = r_vertex_array.write(); @@ -1890,7 +1890,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_canvas_transform", "viewport", "canvas", "offset"), &VisualServer::viewport_set_canvas_transform); ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &VisualServer::viewport_set_transparent_background); ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &VisualServer::viewport_set_global_canvas_transform); - ClassDB::bind_method(D_METHOD("viewport_set_canvas_layer", "viewport", "canvas", "layer"), &VisualServer::viewport_set_canvas_layer); + ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &VisualServer::viewport_set_canvas_stacking); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size"), &VisualServer::viewport_set_shadow_atlas_size); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &VisualServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &VisualServer::viewport_set_msaa); @@ -1915,7 +1915,9 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance", "roughness"), &VisualServer::environment_set_ssr); ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "radius2", "intensity2", "bias", "light_affect", "ao_channel_affect", "color", "quality", "blur", "bilateral_sharpness"), &VisualServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "color", "sun_color", "sun_amount"), &VisualServer::environment_set_fog); - ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "enable", "depth_begin", "depth_curve", "transmit", "transmit_curve"), &VisualServer::environment_set_fog_depth); + + ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "enable", "depth_begin", "depth_end", "depth_curve", "transmit", "transmit_curve"), &VisualServer::environment_set_fog_depth); + ClassDB::bind_method(D_METHOD("environment_set_fog_height", "env", "enable", "min_height", "max_height", "height_curve"), &VisualServer::environment_set_fog_height); ClassDB::bind_method(D_METHOD("scenario_create"), &VisualServer::scenario_create); @@ -1978,7 +1980,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map"), &VisualServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_mesh, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &VisualServer::canvas_item_add_multimesh, DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map", "h_frames", "v_frames"), &VisualServer::canvas_item_add_particles); + ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &VisualServer::canvas_item_add_particles); ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &VisualServer::canvas_item_add_set_transform); ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &VisualServer::canvas_item_add_clip_ignore); ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &VisualServer::canvas_item_set_sort_children_by_y); @@ -2370,6 +2372,7 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096); GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); @@ -2400,6 +2403,8 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/depth_prepass/enable", true); GLOBAL_DEF("rendering/quality/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno"); + + GLOBAL_DEF("rendering/quality/filters/use_nearest_mipmap_filter", false); } VisualServer::~VisualServer() { diff --git a/servers/visual_server.h b/servers/visual_server.h index 9d98fca21b..743e010034 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -61,7 +61,7 @@ protected: RID white_texture; RID test_material; - Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> r_bone_aabb); + Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb); static VisualServer *(*create_func)(); static void _bind_methods(); @@ -644,7 +644,7 @@ public: virtual void viewport_set_transparent_background(RID p_viewport, bool p_enabled) = 0; virtual void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) = 0; - virtual void viewport_set_canvas_layer(RID p_viewport, RID p_canvas, int p_layer) = 0; + virtual void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) = 0; virtual void viewport_set_shadow_atlas_size(RID p_viewport, int p_size) = 0; virtual void viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) = 0; @@ -763,7 +763,7 @@ public: virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, EnvironmentSSAOQuality p_quality, EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) = 0; virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) = 0; - virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0; + virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0; virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0; /* SCENARIO API */ @@ -895,7 +895,7 @@ public: virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0; virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0; - virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map, int p_h_frames, int p_v_frames) = 0; + virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0; virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0; virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0; virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0; |